Re: [PATCH 3/3] rtc: s5m: Make register configuration per S2MPS device to remove exceptions
Hi Krysztof, On Tue, Dec 29, 2015 at 5:53 PM, Krzysztof Kozlowskiwrote: > Before updating time and alarm the driver must set appropriate mask in > UDR register. For that purpose the driver uses common register > configuration and a lot of exceptions per device in the code. The > exceptions are not obvious, for example except the change in the logic > sometimes the fields are swapped (WUDR and AUDR between S2MPS14 and > S2MPS15). This leads to quite complicated code. > > Try to make it more obvious by: > 1. Documenting the UDR masks for devices and operations. > 2. Adding fields in register configuration structure for each operation >(read time, write time and alarm). > 3. Splitting the configuration per S2MPS13, S2MPS14 and S2MPS15 thus >removing exceptions for them. > > Signed-off-by: Krzysztof Kozlowski > > --- > > Tested only on S2MPS11 (Odroid XU4). > --- > drivers/rtc/rtc-s5m.c | 110 > +++- > include/linux/mfd/samsung/rtc.h | 2 + > 2 files changed, 77 insertions(+), 35 deletions(-) > > diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c > index 559db8f72117..7407d7394bb4 100644 > --- a/drivers/rtc/rtc-s5m.c > +++ b/drivers/rtc/rtc-s5m.c > @@ -38,7 +38,22 @@ > */ > #define UDR_READ_RETRY_CNT 5 > > -/* Registers used by the driver which are different between chipsets. */ > +/* > + * Registers used by the driver which are different between chipsets. > + * > + * Operations like read time and write alarm/time require updating > + * specific fields in UDR register. These fields usually are auto-cleared > + * (with some exceptions). > + * > + * Table of operations per device: > + * > + * Device | Write time | Read time | Write alarm > + * = > + * S5M8767| UDR + TIME | | UDR > + * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR > + * S2MPS13| WUDR | RUDR | WUDR + AUDR > + * S2MPS15| WUDR | RUDR | AUDR > + */ > struct s5m_rtc_reg_config { > /* Number of registers used for setting time/alarm0/alarm1 */ > unsigned int regs_count; > @@ -58,8 +73,13 @@ struct s5m_rtc_reg_config { > unsigned int udr_update; > /* Auto-cleared mask in UDR field for writing time and alarm */ > unsigned int autoclear_udr_mask; > - /* Mask for UDR field in 'udr_update' register */ > - unsigned int udr_mask; > + /* > +* Masks in UDR field for time and alarm operations. > +* The read time mask can be 0. Rest should not. > +*/ > + unsigned int read_time_udr_mask; > + unsigned int write_time_udr_mask; > + unsigned int write_alarm_udr_mask; > }; > > /* Register map for S5M8763 and S5M8767 */ > @@ -71,14 +91,44 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = { > .alarm1 = S5M_ALARM1_SEC, > .udr_update = S5M_RTC_UDR_CON, > .autoclear_udr_mask = S5M_RTC_UDR_MASK, > - .udr_mask = S5M_RTC_UDR_MASK, > + .read_time_udr_mask = 0, /* Not needed */ > + .write_time_udr_mask= S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK, > + .write_alarm_udr_mask = S5M_RTC_UDR_MASK, > +}; > + > +/* Register map for S2MPS13 */ > +static const struct s5m_rtc_reg_config s2mps13_rtc_regs = { > + .regs_count = 7, > + .time = S2MPS_RTC_SEC, > + .ctrl = S2MPS_RTC_CTRL, > + .alarm0 = S2MPS_ALARM0_SEC, > + .alarm1 = S2MPS_ALARM1_SEC, > + .udr_update = S2MPS_RTC_UDR_CON, > + .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, > + .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, > + .write_time_udr_mask= S2MPS_RTC_WUDR_MASK, > + .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK, > +}; > + > +/* Register map for S2MPS11/14 */ > +static const struct s5m_rtc_reg_config s2mps14_rtc_regs = { > + .regs_count = 7, > + .time = S2MPS_RTC_SEC, > + .ctrl = S2MPS_RTC_CTRL, > + .alarm0 = S2MPS_ALARM0_SEC, > + .alarm1 = S2MPS_ALARM1_SEC, > + .udr_update = S2MPS_RTC_UDR_CON, > + .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, > + .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, > + .write_time_udr_mask= S2MPS_RTC_WUDR_MASK, > + .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK, > }; > > /* > - * Register map for S2MPS14. > - * It may be also suitable for S2MPS11 but this was not tested. > + * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits > + * are swapped. > */ > -static const struct s5m_rtc_reg_config s2mps_rtc_regs = { > +static const struct s5m_rtc_reg_config s2mps15_rtc_regs = { >
RE: [PATCH] mfd: max77686: Fix parent of rtc device
On Tuesday, December 02, 2014 7:04 PM, Krzysztof Kozłowski wrote: On 02.12.2014 13:45, Yadwinder Singh Brar wrote: rtc have different i2c client than power(pmic) block. So rtc device should sit under its own i2c client in device hierarchy, which reflects in sysfs also. This patch modifies code to register rtc cell with rtc-dev as parent. Without this patch : # ls /sys/class/i2c-adapter/i2c-0/0-0009/ driver max77686-pmic modalias power uevent max77686-clk max77686-rtc name subsystem After applying patch : # ls /sys/class/i2c-adapter/i2c-0/0-0006/ driver/modalias power/ uevent max77686-rtc/ name subsystem/ Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- Or Can we follow another (exhaustive but more cleaner) approach, which will be more like code refactoring and cleanup rather than only fix: Since rtc uses i2c client, which gets created using i2c_new_dummy() and is not shared by any other cell of max77686. So we can covert rtc platform driver itself to i2c client driver. It will also allow to expilicitly describe max77686-rtc in DT which we can't do now. It can be applicable to some other existing and new mfd pmic drivers. Any suggestion/comments ? Hi, What kind of problem is solved by this patch? Let me try to explain once again :) After seeing a message i2c i2c-0: , addr=0x06, .. in dmesg log, I was not able to find any such device in sysfs as well as device tree. There was no device under /sys/class/i2c-dev/i2c-0/device/0-0006/ Isn't something wrong or missing ? This patch fixes that missing parent child relation, which IMO should be correct always, though it causes any major problem or not. Still I am thinking, 0-0006 slave device(rtc) shouldn't also appear in DT? As DT should describe the hardware that we are using. Warm regards, Yadwinder Best regards, Krzysztof --- drivers/mfd/max77686.c | 22 -- 1 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 929795e..22c0948 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -39,10 +39,13 @@ static const struct mfd_cell max77686_devs[] = { { .name = max77686-pmic, }, - { .name = max77686-rtc, }, { .name = max77686-clk, }, }; +static const struct mfd_cell max77686_rtc_dev[] = { + { .name = max77686-rtc, }, +}; + static const struct mfd_cell max77802_devs[] = { { .name = max77802-pmic, }, { .name = max77802-clk, }, @@ -332,14 +335,27 @@ static int max77686_i2c_probe(struct i2c_client *i2c, goto err_del_irqc; } + if (max77686-type == TYPE_MAX77686) { + ret = mfd_add_devices(max77686-rtc-dev, -1, max77686_rtc_dev, + 1, NULL, 0, NULL); + if (ret 0) { + dev_err(max77686-rtc-dev, + failed to add RTC device %d\n, ret); + goto err_del_rtc_irqc; + } + } + ret = mfd_add_devices(max77686-dev, -1, cells, n_devs, NULL, 0, NULL); if (ret 0) { dev_err(i2c-dev, failed to add MFD devices: %d\n, ret); - goto err_del_rtc_irqc; + goto err_del_rtc_dev; } return 0; +err_del_rtc_dev: + if (max77686-type == TYPE_MAX77686) + mfd_remove_devices(max77686-rtc-dev); err_del_rtc_irqc: regmap_del_irq_chip(max77686-irq, max77686-rtc_irq_data); err_del_irqc: @@ -356,6 +372,8 @@ static int max77686_i2c_remove(struct i2c_client *i2c) struct max77686_dev *max77686 = i2c_get_clientdata(i2c); mfd_remove_devices(max77686-dev); + if (max77686-type == TYPE_MAX77686) + mfd_remove_devices(max77686-rtc-dev); regmap_del_irq_chip(max77686-irq, max77686-rtc_irq_data); regmap_del_irq_chip(max77686-irq, max77686-irq_data); -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH] mfd: max77686: Fix parent of rtc device
On Wednesday, December 03, 2014 2:56 PM, Krzysztof Kozlowski wrote: On śro, 2014-12-03 at 14:32 +0530, Yadwinder Singh Brar wrote: On Tuesday, December 02, 2014 7:04 PM, Krzysztof Kozłowski wrote: On 02.12.2014 13:45, Yadwinder Singh Brar wrote: rtc have different i2c client than power(pmic) block. So rtc device should sit under its own i2c client in device hierarchy, which reflects in sysfs also. This patch modifies code to register rtc cell with rtc-dev as parent. Without this patch : # ls /sys/class/i2c-adapter/i2c-0/0-0009/ driver max77686-pmic modalias power uevent max77686-clk max77686-rtc name subsystem After applying patch : # ls /sys/class/i2c-adapter/i2c-0/0-0006/ driver/modalias power/ uevent max77686-rtc/ name subsystem/ Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- Or Can we follow another (exhaustive but more cleaner) approach, which will be more like code refactoring and cleanup rather than only fix: Since rtc uses i2c client, which gets created using i2c_new_dummy() and is not shared by any other cell of max77686. So we can covert rtc platform driver itself to i2c client driver. It will also allow to expilicitly describe max77686-rtc in DT which we can't do now. It can be applicable to some other existing and new mfd pmic drivers. Any suggestion/comments ? Hi, What kind of problem is solved by this patch? Let me try to explain once again :) After seeing a message i2c i2c-0: , addr=0x06, .. in dmesg log, I was not able to find any such device in sysfs as well as device tree. There was no device under /sys/class/i2c-dev/i2c-0/device/0-0006/ Isn't something wrong or missing ? This patch fixes that missing parent child relation, which IMO should be correct always, though it causes any major problem or not. OK, I got your point. I'm fine with both solutions and the patch looks good, so: Reviewed-by: Krzysztof Kozlowski k.kozlow...@samsung.com Thanks for reviewing :). Still I am thinking, 0-0006 slave device(rtc) shouldn't also appear in DT? As DT should describe the hardware that we are using. Your patch properly describes the hardware. However from driver perspective, the RTC here is not an standalone driver and depends on parent (MFD) driver. Hmm ... I can't see any hard dependency. I think rtc can survive as independent i2c device. And rtc(@06) is more like a sibling of existing MFD driver(max77686@09) Although max77686 RTC could have its own DeviceTree node, I think it should still be put under main MFD driver's node, because the parent manages stuff like interrupts. I think it will not sound good to have something like max77686-rtc@06 node under max77686@09 node, since both are kind of siblings. And interrupts should not be a restricting factor, In case of max77686 interrupt source and mask registers for rtc also lie in rtc i2c register bank so we can add an irq_chip from rtc driver itself. Only thing I can see which can be little bit tricky, is providing alarm-pending info(pending interrupt) in alarm_read() callback in rtc as currently its based on MAX77686_REG_STATUS2 which is only common register in power(pmic) register bank of max77686. Though in practical scenarios it may not be non zero, since reading once source register clears this status also, but we may have to keep it for sake of functionality completeness. I can’t see any way(something similar to syscon) for sharing i2c regmap between independent drivers, other than getting reference to regmap from i2c device found by of_find_i2c_device_by_node(). Anyone can suggest better idea? Best Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] mfd: max77686: Fix parent of rtc device
rtc have different i2c client than power(pmic) block. So rtc device should sit under its own i2c client in device hierarchy, which reflects in sysfs also. This patch modifies code to register rtc cell with rtc-dev as parent. Without this patch : driver max77686-pmic modalias power uevent max77686-clk max77686-rtc name subsystem After applying patch : driver/modalias power/ uevent max77686-rtc/ name subsystem/ Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- Or Can we follow another (exhaustive but more cleaner) approach, which will be more like code refactoring and cleanup rather than only fix: Since rtc uses i2c client, which gets created using i2c_new_dummy() and is not shared by any other cell of max77686. So we can covert rtc platform driver itself to i2c client driver. It will also allow to expilicitly describe max77686-rtc in DT which we can't do now. It can be applicable to some other existing and new mfd pmic drivers. Any suggestion/comments ? --- drivers/mfd/max77686.c | 22 -- 1 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 929795e..22c0948 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -39,10 +39,13 @@ static const struct mfd_cell max77686_devs[] = { { .name = max77686-pmic, }, - { .name = max77686-rtc, }, { .name = max77686-clk, }, }; +static const struct mfd_cell max77686_rtc_dev[] = { + { .name = max77686-rtc, }, +}; + static const struct mfd_cell max77802_devs[] = { { .name = max77802-pmic, }, { .name = max77802-clk, }, @@ -332,14 +335,27 @@ static int max77686_i2c_probe(struct i2c_client *i2c, goto err_del_irqc; } + if (max77686-type == TYPE_MAX77686) { + ret = mfd_add_devices(max77686-rtc-dev, -1, max77686_rtc_dev, + 1, NULL, 0, NULL); + if (ret 0) { + dev_err(max77686-rtc-dev, + failed to add RTC device %d\n, ret); + goto err_del_rtc_irqc; + } + } + ret = mfd_add_devices(max77686-dev, -1, cells, n_devs, NULL, 0, NULL); if (ret 0) { dev_err(i2c-dev, failed to add MFD devices: %d\n, ret); - goto err_del_rtc_irqc; + goto err_del_rtc_dev; } return 0; +err_del_rtc_dev: + if (max77686-type == TYPE_MAX77686) + mfd_remove_devices(max77686-rtc-dev); err_del_rtc_irqc: regmap_del_irq_chip(max77686-irq, max77686-rtc_irq_data); err_del_irqc: @@ -356,6 +372,8 @@ static int max77686_i2c_remove(struct i2c_client *i2c) struct max77686_dev *max77686 = i2c_get_clientdata(i2c); mfd_remove_devices(max77686-dev); + if (max77686-type == TYPE_MAX77686) + mfd_remove_devices(max77686-rtc-dev); regmap_del_irq_chip(max77686-irq, max77686-rtc_irq_data); regmap_del_irq_chip(max77686-irq, max77686-irq_data); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] mfd: max77686: Fix parent of rtc device
rtc have different i2c client than power(pmic) block. So rtc device should sit under its own i2c client in device hierarchy, which reflects in sysfs also. This patch modifies code to register rtc cell with rtc-dev as parent. Without this patch : # ls /sys/class/i2c-adapter/i2c-0/0-0009/ driver max77686-pmic modalias power uevent max77686-clk max77686-rtc name subsystem After applying patch : # ls /sys/class/i2c-adapter/i2c-0/0-0006/ driver/modalias power/ uevent max77686-rtc/ name subsystem/ Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- Or Can we follow another (exhaustive but more cleaner) approach, which will be more like code refactoring and cleanup rather than only fix: Since rtc uses i2c client, which gets created using i2c_new_dummy() and is not shared by any other cell of max77686. So we can covert rtc platform driver itself to i2c client driver. It will also allow to expilicitly describe max77686-rtc in DT which we can't do now. It can be applicable to some other existing and new mfd pmic drivers. Any suggestion/comments ? --- drivers/mfd/max77686.c | 22 -- 1 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 929795e..22c0948 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -39,10 +39,13 @@ static const struct mfd_cell max77686_devs[] = { { .name = max77686-pmic, }, - { .name = max77686-rtc, }, { .name = max77686-clk, }, }; +static const struct mfd_cell max77686_rtc_dev[] = { + { .name = max77686-rtc, }, +}; + static const struct mfd_cell max77802_devs[] = { { .name = max77802-pmic, }, { .name = max77802-clk, }, @@ -332,14 +335,27 @@ static int max77686_i2c_probe(struct i2c_client *i2c, goto err_del_irqc; } + if (max77686-type == TYPE_MAX77686) { + ret = mfd_add_devices(max77686-rtc-dev, -1, max77686_rtc_dev, + 1, NULL, 0, NULL); + if (ret 0) { + dev_err(max77686-rtc-dev, + failed to add RTC device %d\n, ret); + goto err_del_rtc_irqc; + } + } + ret = mfd_add_devices(max77686-dev, -1, cells, n_devs, NULL, 0, NULL); if (ret 0) { dev_err(i2c-dev, failed to add MFD devices: %d\n, ret); - goto err_del_rtc_irqc; + goto err_del_rtc_dev; } return 0; +err_del_rtc_dev: + if (max77686-type == TYPE_MAX77686) + mfd_remove_devices(max77686-rtc-dev); err_del_rtc_irqc: regmap_del_irq_chip(max77686-irq, max77686-rtc_irq_data); err_del_irqc: @@ -356,6 +372,8 @@ static int max77686_i2c_remove(struct i2c_client *i2c) struct max77686_dev *max77686 = i2c_get_clientdata(i2c); mfd_remove_devices(max77686-dev); + if (max77686-type == TYPE_MAX77686) + mfd_remove_devices(max77686-rtc-dev); regmap_del_irq_chip(max77686-irq, max77686-rtc_irq_data); regmap_del_irq_chip(max77686-irq, max77686-irq_data); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [1/2] ARM: dts: Fix bootup issue on smdk5250
Hi Kukjin, Subject: RE: [1/2] ARM: dts: Fix bootup issue on smdk5250 Pankaj Dubey wrote: Hi, Hi, Yadwinder, please don't miss [PATCH 1/2] in subject, so that my e-mail client can't filter wrong ;) Sure, but I think your mail client had played some trick, as patches were posted with [PATCH */2] prefix. On Tuesday 18 November 2014 05:38 PM, Yadwinder Singh Brar wrote: With default config on smdk5250 latest tree throws below message : [2.226049] thermal thermal_zone0: critical temperature reached(224 C),shutting down [2.227840] reboot: Failed to start orderly shutdown: forcing the issue and hangs randomly because it reads wrong temperature value. I can't figure out any direct relation between LDO10 and TMU from board schematics which I have. So making LDO10 always-on to fix issue for now. Hmm...strange, I also can't see any relations now...but I need to contact to hardware guy before applying this, this fixes the problem though. Ok, sure it will be good know actual relation from hardware guy. Meanwhile can we get another patch[1] merged which was posted along with patch just because both patches were on same file. Otherwise there is no dependency between them and can be applied independently. Best Regards, Yadwinder [1] : http://www.spinics.net/lists/linux-samsung-soc/msg39107.html Thanks, Kukjin Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com Tested this on SMDK5250 board, system boot is fine now, hence Tested-by: Pankaj Dubey pankaj.du...@samsung.com --- arch/arm/boot/dts/exynos5250-smdk5250.dts |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index bc27cc2..95b5b51 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -190,6 +190,7 @@ regulator-name = P1.8V_LDO_OUT10; regulator-min-microvolt = 180; regulator-max-microvolt = 180; + regulator-always-on; }; ldo11_reg: LDO11 { -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] ARM: dts: Fix bootup issue on smdk5250
With default config on smdk5250 latest tree throws below message : [2.226049] thermal thermal_zone0: critical temperature reached(224 C),shutting down [2.227840] reboot: Failed to start orderly shutdown: forcing the issue and hangs randomly because it reads wrong temperature value. I can't figure out any direct relation between LDO10 and TMU from board schematics which I have. So making LDO10 always-on to fix issue for now. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/boot/dts/exynos5250-smdk5250.dts |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index bc27cc2..95b5b51 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -190,6 +190,7 @@ regulator-name = P1.8V_LDO_OUT10; regulator-min-microvolt = 180; regulator-max-microvolt = 180; + regulator-always-on; }; ldo11_reg: LDO11 { -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] ARM: dts: Add missing irq pinctrl for max77686 on smdk5250
This patch adds pinctrl configuration for using configuring gpx3-2 as an external interrupt from max77686. Though max77686 RTC is enabled and gets probed by default, it doesnt work as its unable to get interrupt. This patch makes max77686 RTC work and also configures it as wakeup source. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/boot/dts/exynos5250-smdk5250.dts | 12 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 95b5b51..19cd918 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -131,6 +131,9 @@ reg = 0x09; interrupt-parent = gpx3; interrupts = 2 IRQ_TYPE_NONE; + pinctrl-names = default; + pinctrl-0 = max77686_irq; + wakeup-source; voltage-regulators { ldo1_reg: LDO1 { @@ -411,3 +414,12 @@ }; }; }; + +pinctrl_0 { + max77686_irq: max77686-irq { + samsung,pins = gpx3-2; + samsung,pin-function = 0xf; + samsung,pin-pud = 0; + samsung,pin-drv = 0; + }; +}; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH] thermal: cpu_cooling: Update always cpufreq policy with thermal constraints
Hello Eduardo Valentin, On Thursday, November 06, 2014 1:19 PM, Eduardo Valentin wrote: Hello Yadwinder, On Thu, Nov 06, 2014 at 04:26:27PM +0530, Yadwinder Singh Brar wrote: Hello Eduardo Valentin, On Thursday, November 06, 2014 2:17 AM, Eduardo Valentin wrote: Hello Yadwinder, On Wed, Nov 05, 2014 at 05:46:25PM +0530, Yadwinder Singh Brar wrote: Existing code updates cupfreq policy only while executing cpufreq_apply_cooling() function (i.e. when notify_device != NOTIFY_INVALID). Correct. The case you mention is when we receive a notification from cpufreq. But also, updates the cpufreq policy when the cooling device changes state, a call from thermal framework. I mentioned thermal framework case only, existing code updates cupfreq policy only when (notify_device != NOTIFY_INVALID), which happens only when notification comes from cpufreq_update_policy while changing cooling device's state(i.e. cpufreq_apply_cooling()). In case of other notifications notify_device is always NOTIFY_INVALID. I see your point. It doesn't apply constraints when cpufreq policy update happens from any other place but it should update the cpufreq policy with thermal constraints every time when there is a cpufreq policy update, to keep state of cpufreq_cooling_device and max_feq of cpufreq policy in sync. I am not sure I follow you here. Can you please elaborate on 'any other places'? Could you please mention (also in the commit log) what are the case the current code does not cover? For instance, the cpufreq_apply_cooling gets called on notification coming from thermal subsystem, and for changes in cpufreq subsystem, cpufreq_thermal_notifier is called. Other places mean possible places from where cpufreq_update_policy() can be called at runtime, an instance in present kernel is cpufreq_resume(). But since cpufreq_update_policy() is an exposed API, I think for robustness, generic cpu cooling should be able to take care of any possible case(in future as well). OK. I understand now. Can you please improve your commit message by adding the descriptions you mentioned here? Sure, will post updated patch. This patch modifies code to maintain a global cpufreq_dev_list and get corresponding cpufreq_cooling_device for policy's cpu from cpufreq_dev_list when there is any policy update. OK. Please give real examples of when the current code fails to catch the event. While resuming cpufreq updates cpufreq_policy for boot cpu and it restores default policy-usr_policy irrespective of cooling device's cpufreq_state since notification gets missed because (notify_device == NOTIFY_INVALID). Another thing, Rather I would say an issue, I observed is that Userspace is able to change max_freq irrespective of cooling device's state, as notification gets missed. Include also the examples above you gave. Have you verified if with this patch the issue with userland goes away? Yes, Userspace is not able to set scaling_max_freq more than the cooling device constraint(cpufreq_val). But I have a question here, Is it OK to silently set scaling_max_freq less than the requested value from userspace ? BR, Eduardo Valentin Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/thermal/cpu_cooling.c | 37 --- -- 1 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 1ab0018..5546278 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -50,15 +50,14 @@ struct cpufreq_cooling_device { unsigned int cpufreq_state; unsigned int cpufreq_val; struct cpumask allowed_cpus; + struct list_head node; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); static unsigned int cpufreq_dev_count; -/* notify_table passes value to the CPUFREQ_ADJUST callback function. */ -#define NOTIFY_INVALID NULL -static struct cpufreq_cooling_device *notify_device; +static LIST_HEAD(cpufreq_dev_list); /** * get_idr - function to get a unique id. @@ -287,15 +286,12 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, cpufreq_device-cpufreq_state = cooling_state; cpufreq_device-cpufreq_val = clip_freq; - notify_device = cpufreq_device; for_each_cpu(cpuid, mask) { if (is_cpufreq_valid(cpuid)) cpufreq_update_policy(cpuid); } - notify_device = NOTIFY_INVALID; - return 0; } @@ -316,21 +312,27 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb
[PATCH v2] thermal: cpu_cooling: Update always cpufreq policy with thermal constraints
Existing code updates cupfreq policy only while executing cpufreq_apply_cooling() function (i.e. when notify_device != NOTIFY_INVALID). It doesn't apply constraints when cpufreq policy update happens from any other place but it should update the cpufreq policy with thermal constraints every time when there is a cpufreq policy update, to keep state of cpufreq_cooling_device and max_feq of cpufreq policy in sync. For instance while resuming cpufreq updates cpufreq_policy and it restores default policy-usr_policy values irrespective of cooling device's cpufreq_state since notification gets missed because (notify_device == NOTIFY_INVALID). Another problem, is that userspace is able to change max_freq irrespective of cooling device's state, as notification gets missed. This patch modifies code to maintain a global cpufreq_dev_list and applies constraints of all matching cooling devices for policy's cpu when there is any policy update(ends up applying the lowest max_freq among the matching cpu cooling devices). This patch also removes redundant check (max_freq policy-user_policy.max), as cpufreq framework takes care of user_policy constraints already where ever required, otherwise its causing an issue while increasing max_freq in normal scenerio as it restores max_freq with policy-user_policy.max which is old (smaller) value. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- changes since v1: - Updated commit message as suggested by Eduardo Valentin - fixed an issue in incresing value of scaling_max_freq from sysfs after decreasing it once in normal thermal conditions also. --- drivers/thermal/cpu_cooling.c | 37 + 1 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 1ab0018..ad09e51 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -50,15 +50,14 @@ struct cpufreq_cooling_device { unsigned int cpufreq_state; unsigned int cpufreq_val; struct cpumask allowed_cpus; + struct list_head node; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); static unsigned int cpufreq_dev_count; -/* notify_table passes value to the CPUFREQ_ADJUST callback function. */ -#define NOTIFY_INVALID NULL -static struct cpufreq_cooling_device *notify_device; +static LIST_HEAD(cpufreq_dev_list); /** * get_idr - function to get a unique id. @@ -287,15 +286,12 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, cpufreq_device-cpufreq_state = cooling_state; cpufreq_device-cpufreq_val = clip_freq; - notify_device = cpufreq_device; for_each_cpu(cpuid, mask) { if (is_cpufreq_valid(cpuid)) cpufreq_update_policy(cpuid); } - notify_device = NOTIFY_INVALID; - return 0; } @@ -316,21 +312,28 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, { struct cpufreq_policy *policy = data; unsigned long max_freq = 0; + struct cpufreq_cooling_device *cpufreq_dev; - if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID) + if (event != CPUFREQ_ADJUST) return 0; - if (cpumask_test_cpu(policy-cpu, notify_device-allowed_cpus)) - max_freq = notify_device-cpufreq_val; - else - return 0; + mutex_lock(cooling_cpufreq_lock); + list_for_each_entry(cpufreq_dev, cpufreq_dev_list, node) { + if (!cpumask_test_cpu(policy-cpu, + cpufreq_dev-allowed_cpus)) + continue; + + if (!cpufreq_dev-cpufreq_val) + cpufreq_dev-cpufreq_val = get_cpu_frequency( + cpumask_any(cpufreq_dev-allowed_cpus), + cpufreq_dev-cpufreq_state); - /* Never exceed user_policy.max */ - if (max_freq policy-user_policy.max) - max_freq = policy-user_policy.max; + max_freq = cpufreq_dev-cpufreq_val; - if (policy-max != max_freq) - cpufreq_verify_within_limits(policy, 0, max_freq); + if (policy-max != max_freq) + cpufreq_verify_within_limits(policy, 0, max_freq); + } + mutex_unlock(cooling_cpufreq_lock); return 0; } @@ -486,6 +489,7 @@ __cpufreq_cooling_register(struct device_node *np, cpufreq_register_notifier(thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); cpufreq_dev_count++; + list_add(cpufreq_dev-node, cpufreq_dev_list); mutex_unlock(cooling_cpufreq_lock); @@ -549,6 +553,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_dev = cdev-devdata; mutex_lock
RE: [PATCH] thermal: cpu_cooling: Update always cpufreq policy with thermal constraints
Hello Eduardo Valentin, On Thursday, November 06, 2014 2:17 AM, Eduardo Valentin wrote: Hello Yadwinder, On Wed, Nov 05, 2014 at 05:46:25PM +0530, Yadwinder Singh Brar wrote: Existing code updates cupfreq policy only while executing cpufreq_apply_cooling() function (i.e. when notify_device != NOTIFY_INVALID). Correct. The case you mention is when we receive a notification from cpufreq. But also, updates the cpufreq policy when the cooling device changes state, a call from thermal framework. I mentioned thermal framework case only, existing code updates cupfreq policy only when (notify_device != NOTIFY_INVALID), which happens only when notification comes from cpufreq_update_policy while changing cooling device's state(i.e. cpufreq_apply_cooling()). In case of other notifications notify_device is always NOTIFY_INVALID. It doesn't apply constraints when cpufreq policy update happens from any other place but it should update the cpufreq policy with thermal constraints every time when there is a cpufreq policy update, to keep state of cpufreq_cooling_device and max_feq of cpufreq policy in sync. I am not sure I follow you here. Can you please elaborate on 'any other places'? Could you please mention (also in the commit log) what are the case the current code does not cover? For instance, the cpufreq_apply_cooling gets called on notification coming from thermal subsystem, and for changes in cpufreq subsystem, cpufreq_thermal_notifier is called. Other places mean possible places from where cpufreq_update_policy() can be called at runtime, an instance in present kernel is cpufreq_resume(). But since cpufreq_update_policy() is an exposed API, I think for robustness, generic cpu cooling should be able to take care of any possible case(in future as well). This patch modifies code to maintain a global cpufreq_dev_list and get corresponding cpufreq_cooling_device for policy's cpu from cpufreq_dev_list when there is any policy update. OK. Please give real examples of when the current code fails to catch the event. While resuming cpufreq updates cpufreq_policy for boot cpu and it restores default policy-usr_policy irrespective of cooling device's cpufreq_state since notification gets missed because (notify_device == NOTIFY_INVALID). Another thing, Rather I would say an issue, I observed is that Userspace is able to change max_freq irrespective of cooling device's state, as notification gets missed. BR, Eduardo Valentin Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/thermal/cpu_cooling.c | 37 --- -- 1 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 1ab0018..5546278 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -50,15 +50,14 @@ struct cpufreq_cooling_device { unsigned int cpufreq_state; unsigned int cpufreq_val; struct cpumask allowed_cpus; + struct list_head node; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); static unsigned int cpufreq_dev_count; -/* notify_table passes value to the CPUFREQ_ADJUST callback function. */ -#define NOTIFY_INVALID NULL -static struct cpufreq_cooling_device *notify_device; +static LIST_HEAD(cpufreq_dev_list); /** * get_idr - function to get a unique id. @@ -287,15 +286,12 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, cpufreq_device-cpufreq_state = cooling_state; cpufreq_device-cpufreq_val = clip_freq; - notify_device = cpufreq_device; for_each_cpu(cpuid, mask) { if (is_cpufreq_valid(cpuid)) cpufreq_update_policy(cpuid); } - notify_device = NOTIFY_INVALID; - return 0; } @@ -316,21 +312,27 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, { struct cpufreq_policy *policy = data; unsigned long max_freq = 0; + struct cpufreq_cooling_device *cpufreq_dev; - if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID) + if (event != CPUFREQ_ADJUST) return 0; - if (cpumask_test_cpu(policy-cpu, notify_device-allowed_cpus)) - max_freq = notify_device-cpufreq_val; - else - return 0; + mutex_lock(cooling_cpufreq_lock); + list_for_each_entry(cpufreq_dev, cpufreq_dev_list, node) { + if (!cpumask_test_cpu(policy-cpu, + cpufreq_dev-allowed_cpus)) + continue; - /* Never exceed user_policy.max */ - if (max_freq policy-user_policy.max) - max_freq = policy-user_policy.max; + max_freq = cpufreq_dev-cpufreq_val; I think I missed to post updated patch, Actually it should be : + if (!cpufreq_dev-cpufreq_val
Re: [PATCH v5 05/14] clk: Add generic driver for Maxim PMIC clocks
Hi Javier, On Thu, Jun 26, 2014 at 11:45 PM, Javier Martinez Canillas javier.marti...@collabora.co.uk wrote: Maxim Integrated Power Management ICs are very similar with regard to their clock outputs. Most of the clock drivers for these chips are duplicating code and are simpler enough that can be converted to use a generic driver to consolidate code and avoid duplication. Signed-off-by: Javier Martinez Canillas javier.marti...@collabora.co.uk Reviewed-by: Krzysztof Kozlowski k.kozlow...@samsung.com --- Changes since v4: - Return recalc 0 if clock isn't enabled in Suggested by Yadwinder Singh Brar. It seems you didn't implement or posted same patch again :) . Changes since v3: - Add current copyright information. Suggested by Krzysztof Kozlowski - Do a single allocation for struct max_gen_clk. Suggested by Krzysztof Kozlowski - Add EXPORT_SYMBOL() for exported symbols. Suggested by Krzysztof Kozlowski drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 1 + drivers/clk/clk-max-gen.c | 195 ++ drivers/clk/clk-max-gen.h | 32 4 files changed, 231 insertions(+) create mode 100644 drivers/clk/clk-max-gen.c create mode 100644 drivers/clk/clk-max-gen.h [ .. ] + +static unsigned long max_gen_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + return 32768; +} Its still same here. + +struct clk_ops max_gen_clk_ops = { + .prepare= max_gen_clk_prepare, + .unprepare = max_gen_clk_unprepare, + .is_prepared= max_gen_clk_is_prepared, + .recalc_rate= max_gen_recalc_rate, +}; +EXPORT_SYMBOL_GPL(max_gen_clk_ops); + +static struct clk *max_gen_clk_register(struct device *dev, + struct max_gen_clk *max_gen) +{ + struct clk *clk; + struct clk_hw *hw = max_gen-hw; + + clk = clk_register(dev, hw); + if (IS_ERR(clk)) + return clk; + + max_gen-lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL); As I suggested in other patch[1] also, its better to use clkdev_alloc() instead of kzalloc() here. + if (!max_gen-lookup) + return ERR_PTR(-ENOMEM); + + max_gen-lookup-con_id = hw-init-name; Also IMO, init-name should be over-written if name is provided in DT, otherwise generic clock-output-names property will go futile, perhaps it should be done before clk_register. Regards, Yadwinder [1] : https://lkml.org/lkml/2014/6/27/197 + max_gen-lookup-clk = clk; + + clkdev_add(max_gen-lookup); + + return clk; +} + +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, + u32 reg, struct clk_init_data *clks_init, int num_init) +{ + int i, ret; + struct max_gen_clk *max_gen_clks; + struct clk **clocks; + struct device *dev = pdev-dev; + + clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL); + if (!clocks) + return -ENOMEM; + + max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk) + * num_init, GFP_KERNEL); + if (!max_gen_clks) + return -ENOMEM; + + for (i = 0; i num_init; i++) { + max_gen_clks[i].regmap = regmap; + max_gen_clks[i].mask = 1 i; + max_gen_clks[i].reg = reg; + max_gen_clks[i].hw.init = clks_init[i]; + + clocks[i] = max_gen_clk_register(dev, max_gen_clks[i]); + if (IS_ERR(clocks[i])) { + ret = PTR_ERR(clocks[i]); + dev_err(dev, failed to register %s\n, + max_gen_clks[i].hw.init-name); + goto err_clocks; + } + } + + platform_set_drvdata(pdev, clocks); + + if (dev-of_node) { + struct clk_onecell_data *of_data; + + of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL); + if (!of_data) { + ret = -ENOMEM; + goto err_clocks; + } + + of_data-clks = clocks; + of_data-clk_num = num_init; + ret = of_clk_add_provider(dev-of_node, of_clk_src_onecell_get, + of_data); + + if (ret) { + dev_err(dev, failed to register OF clock provider\n); + goto err_clocks; + } + } + + return 0; + +err_clocks: + for (--i; i = 0; --i) { + clkdev_drop(max_gen_clks[i].lookup); + clk_unregister(max_gen_clks[i].hw.clk); + } + + return ret; +} +EXPORT_SYMBOL_GPL(max_gen_clk_probe); + +int max_gen_clk_remove(struct
Re: [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
Hi Javier, Sorry for jumping in late, but just one concern mentioned inline. [ .. ] + +static unsigned long max_gen_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + return 32768; +} Isn't more safer(correct), if it check and return 0 when clk is disabled(unprepared) ? Regards, Yadwinder + +struct clk_ops max_gen_clk_ops = { + .prepare= max_gen_clk_prepare, + .unprepare = max_gen_clk_unprepare, + .is_prepared= max_gen_clk_is_prepared, + .recalc_rate= max_gen_recalc_rate, +}; +EXPORT_SYMBOL_GPL(max_gen_clk_ops); + +static struct clk *max_gen_clk_register(struct device *dev, + struct max_gen_clk *max_gen) +{ + struct clk *clk; + struct clk_hw *hw = max_gen-hw; + + clk = clk_register(dev, hw); + if (IS_ERR(clk)) + return clk; + + max_gen-lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL); + if (!max_gen-lookup) + return ERR_PTR(-ENOMEM); + + max_gen-lookup-con_id = hw-init-name; + max_gen-lookup-clk = clk; + + clkdev_add(max_gen-lookup); + + return clk; +} + +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, + u32 reg, struct clk_init_data *clks_init, int num_init) +{ + int i, ret; + struct max_gen_clk *max_gen_clks; + struct clk **clocks; + struct device *dev = pdev-dev; + + clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL); + if (!clocks) + return -ENOMEM; + + max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk) + * num_init, GFP_KERNEL); + if (!max_gen_clks) + return -ENOMEM; + + for (i = 0; i num_init; i++) { + max_gen_clks[i].regmap = regmap; + max_gen_clks[i].mask = 1 i; + max_gen_clks[i].reg = reg; + max_gen_clks[i].hw.init = clks_init[i]; + + clocks[i] = max_gen_clk_register(dev, max_gen_clks[i]); + if (IS_ERR(clocks[i])) { + ret = PTR_ERR(clocks[i]); + dev_err(dev, failed to register %s\n, + max_gen_clks[i].hw.init-name); + goto err_clocks; + } + } + + platform_set_drvdata(pdev, clocks); + + if (dev-of_node) { + struct clk_onecell_data *of_data; + + of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL); + if (!of_data) { + ret = -ENOMEM; + goto err_clocks; + } + + of_data-clks = clocks; + of_data-clk_num = num_init; + ret = of_clk_add_provider(dev-of_node, of_clk_src_onecell_get, + of_data); + + if (ret) { + dev_err(dev, failed to register OF clock provider\n); + goto err_clocks; + } + } + + return 0; + +err_clocks: + for (--i; i = 0; --i) { + clkdev_drop(max_gen_clks[i].lookup); + clk_unregister(max_gen_clks[i].hw.clk); + } + + return ret; +} +EXPORT_SYMBOL_GPL(max_gen_clk_probe); + +int max_gen_clk_remove(struct platform_device *pdev, int num_init) +{ + struct clk **clocks = platform_get_drvdata(pdev); + struct device *dev = pdev-dev.parent; + int i; + + if (dev-of_node) + of_clk_del_provider(dev-of_node); + + for (i = 0; i num_init; i++) { + struct clk_hw *hw = __clk_get_hw(clocks[i]); + struct max_gen_clk *max_gen = to_max_gen_clk(hw); + + clkdev_drop(max_gen-lookup); + clk_unregister(clocks[i]); + } + return 0; +} +EXPORT_SYMBOL_GPL(max_gen_clk_remove); diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h new file mode 100644 index 000..997e86f --- /dev/null +++ b/drivers/clk/clk-max-gen.h @@ -0,0 +1,32 @@ +/* + * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks + * + * Copyright (C) 2014 Google, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __CLK_MAX_GEN_H__ +#define
Re: [PATCH 1/3] regulator: s2mps11: Refactor setting ramp delay
Hi Krzysztof, On Mon, May 26, 2014 at 6:50 PM, Krzysztof Kozlowski k.kozlow...@samsung.com wrote: Prepare for merging the s2mpa01 regulator driver into s2mps11 by: 1. Adding common id for buck regulators. 2. Splitting shared ramp delay settings to match S2MPA01. 3. Adding a configuration of registers for setting ramp delay for each buck regulator. The functionality of the driver should not change as this patch only prepares for supporting S2MPA01 device. Signed-off-by: Krzysztof Kozlowski k.kozlow...@samsung.com --- drivers/regulator/s2mps11.c | 210 ++-- 1 file changed, 144 insertions(+), 66 deletions(-) [snip] - if (ramp_delay s2mps11-ramp_delay34) - s2mps11-ramp_delay34 = ramp_delay; + if (ramp_delay s2mps11-ramp_delay3) + s2mps11-ramp_delay3 = ramp_delay; else - ramp_delay = s2mps11-ramp_delay34; - - ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT; - ramp_reg = S2MPS11_REG_RAMP; + ramp_delay = s2mps11-ramp_delay3; break; case S2MPS11_BUCK4: - enable_shift = S2MPS11_BUCK4_RAMP_EN_SHIFT; if (!ramp_delay) { ramp_enable = 0; break; } - if (ramp_delay s2mps11-ramp_delay34) - s2mps11-ramp_delay34 = ramp_delay; + if (ramp_delay s2mps11-ramp_delay4) + s2mps11-ramp_delay4 = ramp_delay; else - ramp_delay = s2mps11-ramp_delay34; - - ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT; - ramp_reg = S2MPS11_REG_RAMP; + ramp_delay = s2mps11-ramp_delay4; Main rationale behind shared value is completely omitted here, in other cases also, after just giving a NOTE in documentation asking user to make sure to pass same value. It doesn't seem safe, simply leaving a scope of stability issue (in case ramp_delay3 ramp_delay4). Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/3] regulator: s2mps11: Merge S2MPA01 driver
On Mon, May 26, 2014 at 6:50 PM, Krzysztof Kozlowski k.kozlow...@samsung.com wrote: Add S2MPA01 support to the s2mps11 regulator driver. This obsoletes the s2mpa01 regulator driver. Signed-off-by: Krzysztof Kozlowski k.kozlow...@samsung.com @@ -216,30 +250,20 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) ramp_delay = s2mps11-ramp_delay16; break; case S2MPX_BUCK2: - if (!ramp_delay) { - ramp_enable = 0; - break; - } - What if we want to disable ramp_delay from DT ? - s2mps11-ramp_delay2 = ramp_delay; + if (s2mps11-dev_type == S2MPS11X || + ramp_delay s2mps11-ramp_delay2) + s2mps11-ramp_delay2 = ramp_delay; + else /* S2MPA01 ramp_delay = s2mpa01-ramp_delay24 */ + ramp_delay = s2mps11-ramp_delay2; Here ramp_delay = 0(ramp_disable case) is also getting over written, if required to take care of it later. break; case S2MPX_BUCK3: - if (!ramp_delay) { - ramp_enable = 0; - break; - } [snip] - if (!ramp_enable) - goto ramp_disable; - - /* Ramp delay can be enabled/disabled only for buck[2346] */ if (ramp_reg-enable_supported) { + if (ramp_disable) typo ?if (!ramp_enable) / if (!ramp_delay) ? + goto ramp_disable; + Also TBH, I can't get rationale behind this merge, As i can't see considerable reduction in no of C code lines in comp of added complexity. Is there considerable advantage in binary stats of single driver as compare to independent drivers? Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/3] regulator: s2mps11: Merge S2MPA01 driver
On Tue, May 27, 2014 at 1:26 PM, Krzysztof Kozlowski k.kozlow...@samsung.com wrote: On wto, 2014-05-27 at 12:00 +0530, Yadwinder Singh Brar wrote: On Mon, May 26, 2014 at 6:50 PM, Krzysztof Kozlowski k.kozlow...@samsung.com wrote: Add S2MPA01 support to the s2mps11 regulator driver. This obsoletes the s2mpa01 regulator driver. Signed-off-by: Krzysztof Kozlowski k.kozlow...@samsung.com @@ -216,30 +250,20 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) ramp_delay = s2mps11-ramp_delay16; break; case S2MPX_BUCK2: - if (!ramp_delay) { - ramp_enable = 0; - break; - } - What if we want to disable ramp_delay from DT ? It will work OK because at the beginning of s2mps11_set_ramp_delay(): unsigned int ramp_disable = !ramp_delay; This 'ramp_disable' is later used if enable/disable is supported. Oh! I missed you defined a new variable ramp_disable, since ramp_disable is already a label defined in same function. It should be different, i think. - s2mps11-ramp_delay2 = ramp_delay; + if (s2mps11-dev_type == S2MPS11X || + ramp_delay s2mps11-ramp_delay2) + s2mps11-ramp_delay2 = ramp_delay; + else /* S2MPA01 ramp_delay = s2mpa01-ramp_delay24 */ + ramp_delay = s2mps11-ramp_delay2; Here ramp_delay = 0(ramp_disable case) is also getting over written, if required to take care of it later. The same, it is already stored as 'ramp_disable' local variable. break; case S2MPX_BUCK3: - if (!ramp_delay) { - ramp_enable = 0; - break; - } [snip] - if (!ramp_enable) - goto ramp_disable; - - /* Ramp delay can be enabled/disabled only for buck[2346] */ if (ramp_reg-enable_supported) { + if (ramp_disable) typo ?if (!ramp_enable) / if (!ramp_delay) ? I think it is good. I changed the 'ramp_enable' into 'ramp_disable'. ok, but very next statement is goto ramp_disable; which seems odd and obfuscated me. Anyway while reviewing the code I found that I didn't updated the case statements with new BUCKX enum values and the register for enable/disable is hard-coded. I'll fix it. + goto ramp_disable; + Also TBH, I can't get rationale behind this merge, As i can't see considerable reduction in no of C code lines in comp of added complexity. Is there considerable advantage in binary stats of single driver as compare to independent drivers? Overall more code is removed than added: 6 files changed, 454 insertions(+), 719 deletions(-) but you are right that the code for ramp delay is now more complex. What is worth noting now most of ramp delay settings are moved to an array: static const struct s2mpx_ramp_reg s2mps11_ramp_regs[] = { [S2MPX_BUCK1] = s2mps11_ramp_reg(BUCK16), [S2MPX_BUCK2] = s2mps11_buck2346_ramp_reg(BUCK2, RAMP, BUCK2), [S2MPX_BUCK3] = s2mps11_buck2346_ramp_reg(BUCK34, RAMP, BUCK3) instead of being hard-coded into the big switch statement like it was before. Alternative solution to complex ramp delay setting is to just use original functions: s2mps11_set_ramp_delay and s2mpa01_set_ramp_delay. These chips are really similar so having two drivers seems like doubling the effort for maintaining them. I think maintaining a complex or a big file(in case we keep original functions), itself will be an effort consuming thing and moreover binary size of a single driver will also increase considerable as compare to independent drivers (if its not case of multiplatform kernel). Anyways, i think its matter of preference of all, It will be OK, if for others( especially maintainers, Mark ?), its OK. Best Regards, Yadwinder Thanks for comments. Best regards, Krzysztof -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 11/14] regulator: s2mps11: Add opmode for S2MPS14 regulators
Hi, On Thu, Feb 13, 2014 at 2:44 PM, Krzysztof Kozlowski k.kozlow...@samsung.com wrote: S2MPS11/S2MPS14 regulators support different modes of operation: - Always off; - On/Off controlled by pin/GPIO (PWREN/LDOEN/EMMCEN); - Always on; This is very similar to S5M8767 regulator driver which also supports opmodes (although S5M8767 have also low-power mode). This patch adds parsing the operation mode from DTS by reading a op_mode property from regulator child node. First thing since op_mode is not generic property, I think it should be appended with some driver specific prefix. But IMHO its quite generic property used and required by many other PMICs(almost all used by Samsung). I would like to use this opportunity to discuss about adding it as generic regulator constraint(as initial_mode) by providing a default mapping of generic Regulator operating modes(kernel specific) to operating modes supported by hardware in regulator driver itself. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 07/14] regulator: s2mps11: Choose number of supported regulators during probe
Hi, + dev_type = platform_get_device_id(pdev)-driver_data; + switch (dev_type) { + case S2MPS11X: + s2mps11-rdev_num = ARRAY_SIZE(s2mps11_regulators); + regulators = s2mps11_regulators; How about creating and passing copy of s2mps11_regulators at runtime and making s2mps11_regulators __initdata ? Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC v2 1/4] power: asv: Add common ASV support for Samsung SoCs
Hi Tomasz, Sorry for being late. On Sun, Dec 15, 2013 at 10:51 PM, Tomasz Figa tomasz.f...@gmail.com wrote: On Sunday 15 of December 2013 22:30:13 Yadwinder Singh Brar wrote: [snip] + + return NULL; +} + +unsigned int asv_get_volt(enum asv_type_id target_type, + unsigned int target_freq) Do you need this function at all? I believe this is all about populating device's OPP array with frequencies and voltages according to its ASV level. Users will be able to query for required voltage using standard OPP calls then, without a need for ASV specific functions like this one. Yes, I had put a comment in initial version after commit message : Hopefully asv_get_volt() can go out in future, once all users start using OPP library. , which seems to be missed in this version. I had kept it for the time being in initial version, to keep it usable(for testing) with existing cpufreq drivers, which need to reworked and may take time. Hmm, at the moment none of cpufreq drivers use ASV, so they need to be reworked anyway to use it either by the means of a private get_volt function or OPP framework. I agree that OPP may require more work, though. If we decide to keep this function in final version, a comment should be added saying that its usage is deprecated in favor of generic OPP helpers. yes. [snip] + + for (i = 0; i asv_info-nr_dvfs_level; i++) { + if (dev_pm_opp_add(dev, dvfs_table[i].freq * 1000, + dvfs_table[i].volt)) { + dev_warn(dev, Failed to add OPP %d\n, + dvfs_table[i].freq); Hmm, shouldn't it be considered a failure instead? hmm, not really always. Theoretically system with some less(failed to add) levels can work. Moreover I had prefered to keep it only warning, just to keep the behaviour of asv_init_opp_table() similar to that of its counter part of_init_opp_table(). I'm not quite convinced about it. If dev_pm_opp_add() fails, doesn't it mean that something broke seriously in upper layer and we should propagate the error down? Especially when looking at opp_add(), the only failure conditions I can find are memory allocation errors which mean that the system is unlikely to operate correctly anyway. yes, for the time being i had prefered to keep it similar to of_init_opp_table() behaviour wise. If required both should be fixed. [snip] Hmm, I don't see a point of these three separate callbacks above. In general, I'd suggest a different architecture. I'd see this more as: 1) Platform code registers static platform device to instantiate SoC ASV driver. 2) SoC specific ASV driver probes, reads group ID from hardware register, calls register_asv_member() with appropriate DVFS table for detected group. 3) Driver using ASV calls asv_init_opp_table() with its struct device and ASV member name, which causes the ASV code to fill device's operating point using OPP calls. Now client driver has all the information it needs and the work of ASV subsystem is done. The control flow between drivers would be much simpler and no callbacks would have to be called. Architecture stated above seems to be a subset(one possible way of use), of the proposed architecture. If someone really have nothing much to do, he can adopt the above stated approach using this framework also, callbacks are not mandatory. I believe that kernel design principles are to first start with something simple and then if a real need for an extension shows up then extend existing code base with missing features. Sorry, I can't see it complex as with architecture stated above also we have to implement similar structure in drivers as we are already doing now individually in each soc driver. Since we usually have more things to do other than only reading fused group value and simply parsing a table index, so in drivers we have to implement functions to segregate stuff and different people do it in different way. Its an attempt to provide a way to keep structure(functions) similar for easy understanding and factoring out of common code. I fail to see those more things. Could you elaborate a bit about them? Usually we need to implement functions in drivers clearly demarking following : 1- Reading chip info (which can be done at probe time only once for all). 2- Parse/Calculate(modify) ASV group. 3- Any Group specific one time setting. eg ABB settings. 4- Parsing and modifying table ( implementing Voltage locking, if required based on locking info bits). Best Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC v2 1/4] power: asv: Add common ASV support for Samsung SoCs
Hi Abhilash, [ ... ] + * @nr_dvfs_level: Number of dvfs levels supported by member. + * @dvfs_table: Table containing supported ASV freqs and corresponding volts. + * @asv_grp: ASV group of member. + * @flags: ASV flags What are the ASV flags you had in mind ? Right now we don't have any, some thing like delayed init of asv table depending upon dev_node/user(instance) was coming in my mind. Actually I missed to remove it for the time being. Thanks for your review and other suggestions. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC v2 1/4] power: asv: Add common ASV support for Samsung SoCs
Hi Tomasz, Thanks for your thorough review and nice suggestions. [snip] +} + +static struct asv_member *asv_get_mem(enum asv_type_id asv_type) I don't really like this enum based look-up. It's hard to define an enum that covers any possible existing and future platforms that would not be bloated with single platform specific entries. IMHO something string based could be more scalable. Yes, I also agree string based look-up will be better. I was thinking to convert to it, after initial discussion over the APIs. +{ + struct asv_member *asv_mem; + struct asv_info *asv_info; + + list_for_each_entry(asv_mem, asv_list, node) { + asv_info = asv_mem-asv_info; + if (asv_type == asv_info-type) + return asv_mem; + } Don't you need any kind of locking here? A mutex in add_asv_member() suggests that read access to the list should be protected as well. hmmm, yes should be their for completeness of code. + + return NULL; +} + +unsigned int asv_get_volt(enum asv_type_id target_type, + unsigned int target_freq) Do you need this function at all? I believe this is all about populating device's OPP array with frequencies and voltages according to its ASV level. Users will be able to query for required voltage using standard OPP calls then, without a need for ASV specific functions like this one. Yes, I had put a comment in initial version after commit message : Hopefully asv_get_volt() can go out in future, once all users start using OPP library. , which seems to be missed in this version. I had kept it for the time being in initial version, to keep it usable(for testing) with existing cpufreq drivers, which need to reworked and may take time. [snip] + + for (i = 0; i asv_info-nr_dvfs_level; i++) { + if (dev_pm_opp_add(dev, dvfs_table[i].freq * 1000, + dvfs_table[i].volt)) { + dev_warn(dev, Failed to add OPP %d\n, + dvfs_table[i].freq); Hmm, shouldn't it be considered a failure instead? hmm, not really always. Theoretically system with some less(failed to add) levels can work. Moreover I had prefered to keep it only warning, just to keep the behaviour of asv_init_opp_table() similar to that of its counter part of_init_opp_table(). + continue; + } + } + + return 0; +} + +static struct asv_member *asv_init_member(struct asv_info *asv_info) +{ + struct asv_member *asv_mem; + int ret = 0; + + if (!asv_info) { + pr_err(No ASV info provided\n); + return NULL; I'd suggest adopting the ERR_PTR() convention, which allows returning more information about the error. Will it be really usefull here?, as we are not checking return value of any function. Bur for some cases below, i will also like to get it used. + } + + asv_mem = kzalloc(sizeof(*asv_mem), GFP_KERNEL); + if (!asv_mem) { + pr_err(Allocation failed for member: %s\n, asv_info-name); + return NULL; + } [snip] Hmm, I don't see a point of these three separate callbacks above. In general, I'd suggest a different architecture. I'd see this more as: 1) Platform code registers static platform device to instantiate SoC ASV driver. 2) SoC specific ASV driver probes, reads group ID from hardware register, calls register_asv_member() with appropriate DVFS table for detected group. 3) Driver using ASV calls asv_init_opp_table() with its struct device and ASV member name, which causes the ASV code to fill device's operating point using OPP calls. Now client driver has all the information it needs and the work of ASV subsystem is done. The control flow between drivers would be much simpler and no callbacks would have to be called. Architecture stated above seems to be a subset(one possible way of use), of the proposed architecture. If someone really have nothing much to do, he can adopt the above stated approach using this framework also, callbacks are not mandatory. Since we usually have more things to do other than only reading fused group value and simply parsing a table index, so in drivers we have to implement functions to segregate stuff and different people do it in different way. Its an attempt to provide a way to keep structure(functions) similar for easy understanding and factoring out of common code. Moreover, I feels need of callbacks if we have to do something depending upon(specific) the user/instance of ASV member. One thing came in my mind was dev_node may be required if we may think of parsing ASV table from DT and may be more things in future. I would like to get rectified, other nit/suggestions stated by you in next version. Thanks Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a
Re: [RFC 0/4] Add basic support for ASV
Hi MyungJoo, Thanks for your review. On Wed, Nov 13, 2013 at 11:33 AM, MyungJoo Ham myungjoo@samsung.com wrote: On Mon, Nov 11, 2013 at 11:27 PM, Yadwinder Singh Brar yadi.bra...@gmail.com wrote: gentle ping for suggestions/reviews .. On Wed, Sep 11, 2013 at 8:14 PM, Yadwinder Singh Brar yadi.b...@samsung.com wrote: This series is to add basic common infrastructure for ASV. Basically ASV is a technique used on samsung SoCs, which provides the recommended supply voltage for dvfs of arm, mif etc. For a given operating frequency, the voltage is recommended based on SoC's ASV group. ASV group gets fussed on SoCs during process of mass production. ASV is an instance of AVS. Please recondier and try to reuse what's already there (drivers/power/avs) Quote from drivers/power/avs/Kconfig: At a given operating point the voltage is adapted depending on static factors (chip manufacturing process) and dynamic factors (temperature depending performance). It seems that the current ASV is subset of AVS. Yes, both seems to be for similar purpose but still significantly different from each other. I would like to describe/differentiate it little bit here for explanation for others, that it is AVS(adaptive voltage scaling) which seems to be an IP/module doing adaptive voltage scaling where as ours is ASV(Adaptive scaling voltage), it provides only (adaptive) voltage for scaling to other drivers. Although the current implementation of AVS does not provide significant infrastructure to its sisters, we may start by sharing the directory. Yes, we can just share directory only right now, other then that i didn't see any thing can be common. Firstly i had put in that directory itself, later being doubtful i moved it to new directory but we can share directory. Any ideas/comments from others ? Regards, Yadwinder Added Jean Pihet, who has submitted AVS (TI). Cheers, MyungJoo. This series includes: - basic common infrastructue for ASV. It provides common APIs for user drivers like cpufreq devfreq and and an interface for SoC specific drivers to register ASV members(instances) - a common platform driver to register ASV members for exynos SoCs - an example providing minimal support (only for ARM ASV) for exynos5250 chips Its just basic skelton which I wanted to get it reviewed or discussed in early stage, before going ahead on further development based on it. Presently example is based on static ASV table provided in SoC specific file, which I expects to go into DT. But exactly how and where needs to be discussed, may be in next revisions once we get through the basic skelton. Also the location of driver in kernel may also seem odd to someone and many more things :). Looking for your valuable reviews and suggestions. Thanks Yadwinder Singh Brar (4): power: asv: Add common ASV support for samsung SoCs power: asv: Add a common asv driver for exynos SoCs. power: asv: Add support for exynos5250 arm: exynos5: Register static platform device for ASV. arch/arm/mach-exynos/mach-exynos5-dt.c |3 + drivers/power/Kconfig|1 + drivers/power/Makefile |1 + drivers/power/asv/Kconfig| 24 drivers/power/asv/Makefile |2 + drivers/power/asv/exynos-asv.c | 81 ++ drivers/power/asv/exynos-asv.h | 22 drivers/power/asv/exynos5250-asv.c | 141 drivers/power/asv/samsung-asv.c | 175 ++ include/linux/power/samsung-asv-driver.h | 61 +++ include/linux/power/samsung-asv.h| 37 +++ 11 files changed, 548 insertions(+), 0 deletions(-) create mode 100644 drivers/power/asv/Kconfig create mode 100644 drivers/power/asv/Makefile create mode 100644 drivers/power/asv/exynos-asv.c create mode 100644 drivers/power/asv/exynos-asv.h create mode 100644 drivers/power/asv/exynos5250-asv.c create mode 100644 drivers/power/asv/samsung-asv.c create mode 100644 include/linux/power/samsung-asv-driver.h create mode 100644 include/linux/power/samsung-asv.h ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- MyungJoo Ham, Ph.D. System S/W Lab, S/W Center, Samsung Electronics -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC 0/4] Add basic support for ASV
[adding Sachin] Hi Tomasz, On Fri, Nov 15, 2013 at 12:06 AM, Tomasz Figa tomasz.f...@gmail.com wrote: Hi Yadwinder, On Monday 11 of November 2013 23:27:08 Yadwinder Singh Brar wrote: gentle ping for suggestions/reviews .. Hmm, I must have somehow missed this series when you orignally sent it. Can I ask you to resend it, as I don't have it in my e-mail client archive any longer? While at it, I would also ask you to add my private e-mail address (this one) and linux-pm mailing list to Cc list. hmm, I am on travel still for few more days, so it may be difficult for me to resend it quickly. But I think Sachin may help me here. Sachin can you please rebase and repost it ? Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/4] clk: clk-s2mps11: Refactor for including support for other MFD clocks
On Thu, Oct 31, 2013 at 3:48 PM, Tushar Behera tushar.beh...@linaro.org wrote: The clocks in S2MPS11 and S5M8767 are managed in the same way, baring a difference in the register offset. It would be better to update existing S2MPS11 driver to support the clocks in S5M8767, rather than creating an almost duplicate driver altogether. Signed-off-by: Tushar Behera tushar.beh...@linaro.org CC: Yadwinder Singh Brar yadi.b...@samsung.com CC: Mike Turquette mturque...@linaro.org --- Reviewed-by: Yadwinder Singh Brar yadi.b...@samsung.com Regards, Yadwinder drivers/clk/clk-s2mps11.c | 20 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 7be41e6..2262cb4 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -48,6 +48,7 @@ struct s2mps11_clk { struct clk_lookup *lookup; u32 mask; bool enabled; + unsigned int reg; }; static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw) @@ -61,7 +62,7 @@ static int s2mps11_clk_prepare(struct clk_hw *hw) int ret; ret = regmap_update_bits(s2mps11-iodev-regmap, - S2MPS11_REG_RTC_CTRL, +s2mps11-reg, s2mps11-mask, s2mps11-mask); if (!ret) s2mps11-enabled = true; @@ -74,7 +75,7 @@ static void s2mps11_clk_unprepare(struct clk_hw *hw) struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw); int ret; - ret = regmap_update_bits(s2mps11-iodev-regmap, S2MPS11_REG_RTC_CTRL, + ret = regmap_update_bits(s2mps11-iodev-regmap, s2mps11-reg, s2mps11-mask, ~s2mps11-mask); if (!ret) @@ -155,6 +156,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) struct sec_pmic_dev *iodev = dev_get_drvdata(pdev-dev.parent); struct s2mps11_clk *s2mps11_clks, *s2mps11_clk; struct device_node *clk_np = NULL; + unsigned int s2mps11_reg; int i, ret = 0; u32 val; @@ -169,13 +171,23 @@ static int s2mps11_clk_probe(struct platform_device *pdev) if (IS_ERR(clk_np)) return PTR_ERR(clk_np); + switch(platform_get_device_id(pdev)-driver_data) { + case S2MPS11X: + s2mps11_reg = S2MPS11_REG_RTC_CTRL; + break; + default: + dev_err(pdev-dev, Invalid device type\n); + return -EINVAL; + }; + for (i = 0; i S2MPS11_CLKS_NUM; i++, s2mps11_clk++) { s2mps11_clk-iodev = iodev; s2mps11_clk-hw.init = s2mps11_clks_init[i]; s2mps11_clk-mask = 1 i; + s2mps11_clk-reg = s2mps11_reg; ret = regmap_read(s2mps11_clk-iodev-regmap, - S2MPS11_REG_RTC_CTRL, val); + s2mps11_clk-reg, val); if (ret 0) goto err_reg; @@ -241,7 +253,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev) } static const struct platform_device_id s2mps11_clk_id[] = { - { s2mps11-clk, 0}, + { s2mps11-clk, S2MPS11X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/4] clk: clk-s2mps11: Add support for clocks in S5M8767 MFD
On Thu, Oct 31, 2013 at 3:48 PM, Tushar Behera tushar.beh...@linaro.org wrote: Since clock operation within S2MPS11 and S5M8767 are similar, we can support both the devices within a single driver. Signed-off-by: Tushar Behera tushar.beh...@linaro.org CC: Yadwinder Singh Brar yadi.b...@samsung.com CC: Mike Turquette mturque...@linaro.org --- Reviewed-by: Yadwinder Singh Brar yadi.b...@samsung.com Regards, Yadwinder drivers/clk/Kconfig |6 -- drivers/clk/clk-s2mps11.c |5 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 5c51115..7f2aef2 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -65,10 +65,12 @@ config COMMON_CLK_SI5351 generators. config COMMON_CLK_S2MPS11 - tristate Clock driver for S2MPS11 MFD + tristate Clock driver for S2MPS11/S5M8767 MFD depends on MFD_SEC_CORE ---help--- - This driver supports S2MPS11 crystal oscillator clock. + This driver supports S2MPS11/S5M8767 crystal oscillator clock. These + multi-function devices have 3 fixed-rate oscillators, clocked at + 32KHz each. config CLK_TWL6040 tristate External McPDM functional clock from twl6040 diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 2262cb4..19c075c 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -27,6 +27,7 @@ #include linux/clk-provider.h #include linux/platform_device.h #include linux/mfd/samsung/s2mps11.h +#include linux/mfd/samsung/s5m8767.h #include linux/mfd/samsung/core.h #define s2mps11_name(a) (a-hw.init-name) @@ -175,6 +176,9 @@ static int s2mps11_clk_probe(struct platform_device *pdev) case S2MPS11X: s2mps11_reg = S2MPS11_REG_RTC_CTRL; break; + case S5M8767X: + s2mps11_reg = S5M8767_REG_CTRL1; + break; default: dev_err(pdev-dev, Invalid device type\n); return -EINVAL; @@ -254,6 +258,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev) static const struct platform_device_id s2mps11_clk_id[] = { { s2mps11-clk, S2MPS11X}, + { s5m8767-clk, S5M8767X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); -- 1.7.9.5 ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC 0/4] Add basic support for ASV
gentle ping for suggestions/reviews .. On Wed, Sep 11, 2013 at 8:14 PM, Yadwinder Singh Brar yadi.b...@samsung.com wrote: This series is to add basic common infrastructure for ASV. Basically ASV is a technique used on samsung SoCs, which provides the recommended supply voltage for dvfs of arm, mif etc. For a given operating frequency, the voltage is recommended based on SoC's ASV group. ASV group gets fussed on SoCs during process of mass production. This series includes: - basic common infrastructue for ASV. It provides common APIs for user drivers like cpufreq devfreq and and an interface for SoC specific drivers to register ASV members(instances) - a common platform driver to register ASV members for exynos SoCs - an example providing minimal support (only for ARM ASV) for exynos5250 chips Its just basic skelton which I wanted to get it reviewed or discussed in early stage, before going ahead on further development based on it. Presently example is based on static ASV table provided in SoC specific file, which I expects to go into DT. But exactly how and where needs to be discussed, may be in next revisions once we get through the basic skelton. Also the location of driver in kernel may also seem odd to someone and many more things :). Looking for your valuable reviews and suggestions. Thanks Yadwinder Singh Brar (4): power: asv: Add common ASV support for samsung SoCs power: asv: Add a common asv driver for exynos SoCs. power: asv: Add support for exynos5250 arm: exynos5: Register static platform device for ASV. arch/arm/mach-exynos/mach-exynos5-dt.c |3 + drivers/power/Kconfig|1 + drivers/power/Makefile |1 + drivers/power/asv/Kconfig| 24 drivers/power/asv/Makefile |2 + drivers/power/asv/exynos-asv.c | 81 ++ drivers/power/asv/exynos-asv.h | 22 drivers/power/asv/exynos5250-asv.c | 141 drivers/power/asv/samsung-asv.c | 175 ++ include/linux/power/samsung-asv-driver.h | 61 +++ include/linux/power/samsung-asv.h| 37 +++ 11 files changed, 548 insertions(+), 0 deletions(-) create mode 100644 drivers/power/asv/Kconfig create mode 100644 drivers/power/asv/Makefile create mode 100644 drivers/power/asv/exynos-asv.c create mode 100644 drivers/power/asv/exynos-asv.h create mode 100644 drivers/power/asv/exynos5250-asv.c create mode 100644 drivers/power/asv/samsung-asv.c create mode 100644 include/linux/power/samsung-asv-driver.h create mode 100644 include/linux/power/samsung-asv.h ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/9] clk: samsung: exynos4: Move suspend/resume handling to SoC driver
Hi Tomasz, [ ... ] /* * list of controller registers to be saved and restored during a * suspend/resume cycle. @@ -288,6 +299,70 @@ static unsigned long exynos4_clk_regs[] __initdata = { GATE_IP_CPU, }; +static int exynos4_clk_suspend(void) +{ + samsung_clk_save(reg_base, exynos4_save_common, + ARRAY_SIZE(exynos4_clk_regs)); a doubt here, Is sizeof(exynos4_clk_regs) works with exynos4_clk_regs[] as __initdata ? + + if (exynos4_soc == EXYNOS4210) + samsung_clk_save(reg_base, exynos4_save_soc, + ARRAY_SIZE(exynos4210_clk_save)); [ ... ] +static void exynos4_clk_sleep_init(void) I think, this fuction can be placed in __init section. Same in other patches as well. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/9] clk: samsung: exynos4: Move suspend/resume handling to SoC driver
On Thu, Oct 17, 2013 at 7:46 PM, Tomasz Figa t.f...@samsung.com wrote: On Thursday 17 of October 2013 19:12:08 Yadwinder Singh Brar wrote: Hi Tomasz, [ ... ] /* * list of controller registers to be saved and restored during a * suspend/resume cycle. @@ -288,6 +299,70 @@ static unsigned long exynos4_clk_regs[] __initdata = { GATE_IP_CPU, }; +static int exynos4_clk_suspend(void) +{ + samsung_clk_save(reg_base, exynos4_save_common, + ARRAY_SIZE(exynos4_clk_regs)); a doubt here, Is sizeof(exynos4_clk_regs) works with exynos4_clk_regs[] as __initdata ? Hmm, this is a compile time constant, so I don't see why it couldn't work. why this doubt came in mind is sizeof() is a operator.. like we can use sizeof(x++). -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/3] clk: samsung: Add clock driver for s5pc100
Hi Tomasz, On Thu, Sep 26, 2013 at 7:30 PM, Tomasz Figa t.f...@samsung.com wrote: Hi Yadwinder, I haven't reviewed this series yet, but let me clarify some things from your comments. On Thursday 26 of September 2013 17:38:58 Yadwinder Singh Brar wrote: + +/* Helper macros to define clock arrays. */ +#define FIXED_RATE_CLOCKS(name)\ + static struct samsung_fixed_rate_clock name[] +#define MUX_CLOCKS(name) \ + static struct samsung_mux_clock name[] +#define DIV_CLOCKS(name) \ + static struct samsung_div_clock name[] +#define GATE_CLOCKS(name) \ + static struct samsung_gate_clock name[] + These macros seems little bit odd in our common practice, perhaps these are making code harder to read below. They allow array declaration to fit into single line. I agree that it is not particularly easy to read at first sight, but shouldn't really be much of nuisance. Defining a macro just to use once/twice, especially hiding the definition of some array, doesn't looks justified. In addition, most of this driver is based on macros like this, e.g. GATE(), MUX(), PNAME(), etc. +PNAME(mout_i2s_2_p) = { + fout_epll, + i2scdclk0, + dout_audio0, + none +}; + Using one line per parent isn't increasing length of file unnecessarily? I believe this improves readability. Do we really care about size of source code that much, over readability? yes, its looks little bit clean but in this case I felt, its making the traversability in file difficult due to length of file. + ALIAS(SCLK_AUDIO0, soc-audio.0, sclk_audio), + ALIAS(SCLK_AUDIO1, soc-audio.1, sclk_audio), + ALIAS(SCLK_AUDIO2, soc-audio.2, sclk_audio), + ALIAS(KEYIF, NULL, keypad), + + ALIAS(MFC, s5p-mfc, sclk_mfc), + ALIAS(G2D, s5p-g2d, fimg2d), + +}; + Any reason/hidden advantage for using a separate of ALIAS, instead of using MUX_A/GATE_A ? Yes, not even hidden. Alias is not a property of clock. One clock can have multiple aliases, e.g. the same clock being input to multiple devices. Yes, its required if same clk has different alias for different devices, but while using same alias for different(all, in this case) devices, doesn't seems advantageous. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] cpufreq: exynos4x12: Use the common clock framework to set APLL clock rate
Hi Tomasz, On Wed, Sep 25, 2013 at 4:52 PM, Lukasz Majewski l.majew...@samsung.com wrote: In the exynos4x12_set_apll() function, the APLL frequency is set with direct register manipulation. Such approach is not allowed in the common clock framework. The frequency is changed, but the corresponding clock value is not updated. This causes wrong frequency read from cpufreq's cpuinfo_cur_freq sysfs attribute. This patch looks incomplete, leaving the driver in untidy state, perhaps its doesn't fix the above stated problem completely. what about if (!exynos4x12_pms_change(old_index, new_index)) becomes true? IMHO, this driver needs lot more work in addition to this patch to cleanly and completely move the cpufreq driver to common clock framework. I agree that the other case needs to be handled as well. Basically the whole conditional block dependent on exynos4x12_pms_change() can be safely dropped, because this condition is already handled in PLL driver. Exactly! Lukasz is already working on further rework of this driver to clean it up from legacy code, but this will have to wait for 3.13, as 3.12 is already in rc stage and only fixes can be accepted for it. For fixing this issue urgently, setting CLK_GET_RATE_NOCACHE for apll in clk driver can also be quicker fix. Unfortunately this is not how this flag works. It only makes clk_get_rate() call -recalc_rate() operation of the clock instead of instantly returning cached rate - it doesn't seem to work recursively. hmm.. yes it can't help in our case as it recursively walks only the subtree of clk but in our case we are changing rate of parent. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/3] clk: samsung: Add clock driver for s5pc100
Hi Mateusz, After a quick view, just few things regarding coding styles. [...] +#defineGENERAL_STATUS 0x0104 +#defineCAM_MUX_SEL 0x0300 +#defineMIXER_OUT_SEL 0x0304 +#defineLPMP3_MODE_SEL 0x0308 +#define MIPI_PHY_CON0 0x0400 +#define MIPI_PHY_CON1 0x0414 +#define HDMI_PHY_CON0 0x0420 How about aligning all above with same no. of tabs? + +/* Helper macros to define clock arrays. */ +#define FIXED_RATE_CLOCKS(name)\ + static struct samsung_fixed_rate_clock name[] +#define MUX_CLOCKS(name) \ + static struct samsung_mux_clock name[] +#define DIV_CLOCKS(name) \ + static struct samsung_div_clock name[] +#define GATE_CLOCKS(name) \ + static struct samsung_gate_clock name[] + These macros seems little bit odd in our common practice, perhaps these are making code harder to read below. +/* Helper macros for gate types present on S5PC100. */ +#define GATE_BUS(_id, cname, pname, o, b) \ + GATE(_id, cname, pname, o, b, 0, 0) +#define GATE_SCLK(_id, cname, pname, o, b) \ + GATE(_id, cname, pname, o, b, CLK_SET_RATE_PARENT, 0) +#define GATE_ON(_id, cname, pname, o, b) \ + GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0) + [...] +PNAME(mout_hclk_2_p) = { + fout_epll, + i2scdclk0 +}; + +PNAME(mout_i2s_2_p) = { + fout_epll, + i2scdclk0, + dout_audio0, + none +}; + Using one line per parent isn't increasing length of file unnecessarily? [ ... ] + +/* list of all parent clock list */ +static struct samsung_clock_alias s5pc100_clock_aliases[] = { + ALIAS(FIMC0, s5pc100-fimc.0, fimc), + ALIAS(FIMC1, s5pc100-fimc.1, fimc), + ALIAS(FIMC2, s5pc100-fimc.2, fimc), + ALIAS(MOUT_FIMC2, NULL, mout_fimc2), + ALIAS(MOUT_FIMC1, NULL, mout_fimc1), + ALIAS(MOUT_FIMC0, NULL, mout_fimc0), + ALIAS(SCLK_FIMC0, s5pc100-fimc.0, sclk_fimc), + ALIAS(SCLK_FIMC1, s5pc100-fimc.1, sclk_fimc), + ALIAS(SCLK_FIMC2, s5pc100-fimc.2, sclk_fimc), + + ALIAS(MOUT_APLL, NULL, mout_apll), + ALIAS(MOUT_MPLL, NULL, mout_mpll), + ALIAS(MOUT_EPLL, NULL, mout_epll), + ALIAS(MOUT_HPLL, NULL, mout_hpll), + ALIAS(MOUT_HPLL, NULL, sclk_hpll), + ALIAS(UART0, s3c6400-uart.0, uart), + ALIAS(UART1, s3c6400-uart.1, uart), + ALIAS(UART2, s3c6400-uart.2, uart), + ALIAS(UART3, s3c6400-uart.3, uart), + ALIAS(UART0, s3c6400-uart.0, clk_uart_baud0), + ALIAS(UART1, s3c6400-uart.1, clk_uart_baud0), + ALIAS(UART2, s3c6400-uart.2, clk_uart_baud0), + ALIAS(UART3, s3c6400-uart.3, clk_uart_baud0), + ALIAS(UART0, s3c6400-uart.0, clk_uart_baud2), + ALIAS(UART1, s3c6400-uart.1, clk_uart_baud2), + ALIAS(UART2, s3c6400-uart.2, clk_uart_baud2), + ALIAS(UART3, s3c6400-uart.3, clk_uart_baud2), + ALIAS(SCLK_UART, s3c6400-uart.0, clk_uart_baud3), + ALIAS(SCLK_UART, s3c6400-uart.1, clk_uart_baud3), + ALIAS(SCLK_UART, s3c6400-uart.2, clk_uart_baud3), + ALIAS(SCLK_UART, s3c6400-uart.3, clk_uart_baud3), + + ALIAS(HSMMC0, s3c-sdhci.0, hsmmc), + ALIAS(HSMMC1, s3c-sdhci.1, hsmmc), + ALIAS(HSMMC2, s3c-sdhci.2, hsmmc), + ALIAS(HSMMC0, s3c-sdhci.0, mmc_busclk.0), + ALIAS(HSMMC1, s3c-sdhci.1, mmc_busclk.0), + ALIAS(HSMMC2, s3c-sdhci.2, mmc_busclk.0), + ALIAS(SCLK_MMC0, s3c-sdhci.0, mmc_busclk.2), + ALIAS(SCLK_MMC1, s3c-sdhci.1, mmc_busclk.2), + ALIAS(SCLK_MMC2, s3c-sdhci.2, mmc_busclk.2), + ALIAS(SCLK_MMC0_48, s3c-sdhci.0, mmc_busclk.3), + ALIAS(SCLK_MMC1_48, s3c-sdhci.1, mmc_busclk.3), + ALIAS(SCLK_MMC2_48, s3c-sdhci.2, mmc_busclk.3), + + ALIAS(SPI0, s5pc100-spi.0, spi), + ALIAS(SPI1, s5pc100-spi.1, spi), + ALIAS(SPI2, s5pc100-spi.2, spi), + ALIAS(SPI0, s5pc100-spi.0, spi_busclk0), + ALIAS(SPI1, s5pc100-spi.1, spi_busclk0), + ALIAS(SPI2, s5pc100-spi.2, spi_busclk0), + ALIAS(SCLK_SPI0_48, s5pc100-spi.0, spi_busclk1), + ALIAS(SCLK_SPI1_48, s5pc100-spi.1, spi_busclk1), + ALIAS(SCLK_SPI2_48, s5pc100-spi.2, spi_busclk1), + ALIAS(SCLK_SPI0, s5pc100-spi.0, spi_busclk2), + ALIAS(SCLK_SPI1, s5pc100-spi.1, spi_busclk2), + ALIAS(SCLK_SPI2, s5pc100-spi.2, spi_busclk2), + ALIAS(PDMA0, dma-pl330.0, apb_pclk), + ALIAS(PDMA1, dma-pl330.1, apb_pclk), + ALIAS(PWM, NULL, timers), + + ALIAS(JPEG, NULL, jpeg), + ALIAS(MFC, s5p-mfc, mfc), + ALIAS(TV, s5p-sdo, dac), + ALIAS(MIXER, s5p-mixer, mixer), + ALIAS(VP, s5p-mixer, vp), + ALIAS(HDMI, s5p-hdmi, hdmi), + ALIAS(SCLK_HDMI, s5p-hdmi, hdmiphy), + + ALIAS(USB_OTG, NULL, otg), + ALIAS(USB_HOST, NULL, usb-host), +
Re: [PATCH 1/2] cpufreq: exynos4x12: Use the common clock framework to set APLL clock rate
Hi Lukasz, On Wed, Sep 25, 2013 at 4:52 PM, Lukasz Majewski l.majew...@samsung.com wrote: In the exynos4x12_set_apll() function, the APLL frequency is set with direct register manipulation. Such approach is not allowed in the common clock framework. The frequency is changed, but the corresponding clock value is not updated. This causes wrong frequency read from cpufreq's cpuinfo_cur_freq sysfs attribute. This patch looks incomplete, leaving the driver in untidy state, perhaps its doesn't fix the above stated problem completely. what about if (!exynos4x12_pms_change(old_index, new_index)) becomes true? IMHO, this driver needs lot more work in addition to this patch to cleanly and completely move the cpufreq driver to common clock framework. For fixing this issue urgently, setting CLK_GET_RATE_NOCACHE for apll in clk driver can also be quicker fix. Regards, Yadwinder Tested at: - Exynos4412 - Trats2 board (linux 3.12-rc1) Signed-off-by: Lukasz Majewski l.majew...@samsung.com Reviewed-by: Bartlomiej Zolnierkiewicz b.zolnier...@samsung.com Reviewed-by: Tomasz Figa t.f...@samsung.com --- drivers/cpufreq/exynos4x12-cpufreq.c | 23 --- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index 08b7477..b2f51c9 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c @@ -128,9 +128,9 @@ static void exynos4x12_set_clkdiv(unsigned int div_index) static void exynos4x12_set_apll(unsigned int index) { - unsigned int tmp, pdiv; + unsigned int tmp, freq = apll_freq_4x12[index].freq; - /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ + /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ clk_set_parent(moutcore, mout_mpll); do { @@ -140,24 +140,9 @@ static void exynos4x12_set_apll(unsigned int index) tmp = 0x7; } while (tmp != 0x2); - /* 2. Set APLL Lock time */ - pdiv = ((apll_freq_4x12[index].mps 8) 0x3f); + clk_set_rate(mout_apll, freq * 1000); - __raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK); - - /* 3. Change PLL PMS values */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp = ~((0x3ff 16) | (0x3f 8) | (0x7 0)); - tmp |= apll_freq_4x12[index].mps; - __raw_writel(tmp, EXYNOS4_APLL_CON0); - - /* 4. wait_lock_time */ - do { - cpu_relax(); - tmp = __raw_readl(EXYNOS4_APLL_CON0); - } while (!(tmp (0x1 EXYNOS4_APLLCON0_LOCKED_SHIFT))); - - /* 5. MUX_CORE_SEL = APLL */ + /* MUX_CORE_SEL = APLL */ clk_set_parent(moutcore, mout_apll); do { -- 1.7.10.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC 0/4] Add basic support for ASV
This series is to add basic common infrastructure for ASV. Basically ASV is a technique used on samsung SoCs, which provides the recommended supply voltage for dvfs of arm, mif etc. For a given operating frequency, the voltage is recommended based on SoC's ASV group. ASV group gets fussed on SoCs during process of mass production. This series includes: - basic common infrastructue for ASV. It provides common APIs for user drivers like cpufreq devfreq and and an interface for SoC specific drivers to register ASV members(instances) - a common platform driver to register ASV members for exynos SoCs - an example providing minimal support (only for ARM ASV) for exynos5250 chips Its just basic skelton which I wanted to get it reviewed or discussed in early stage, before going ahead on further development based on it. Presently example is based on static ASV table provided in SoC specific file, which I expects to go into DT. But exactly how and where needs to be discussed, may be in next revisions once we get through the basic skelton. Also the location of driver in kernel may also seem odd to someone and many more things :). Looking for your valuable reviews and suggestions. Thanks Yadwinder Singh Brar (4): power: asv: Add common ASV support for samsung SoCs power: asv: Add a common asv driver for exynos SoCs. power: asv: Add support for exynos5250 arm: exynos5: Register static platform device for ASV. arch/arm/mach-exynos/mach-exynos5-dt.c |3 + drivers/power/Kconfig|1 + drivers/power/Makefile |1 + drivers/power/asv/Kconfig| 24 drivers/power/asv/Makefile |2 + drivers/power/asv/exynos-asv.c | 81 ++ drivers/power/asv/exynos-asv.h | 22 drivers/power/asv/exynos5250-asv.c | 141 drivers/power/asv/samsung-asv.c | 175 ++ include/linux/power/samsung-asv-driver.h | 61 +++ include/linux/power/samsung-asv.h| 37 +++ 11 files changed, 548 insertions(+), 0 deletions(-) create mode 100644 drivers/power/asv/Kconfig create mode 100644 drivers/power/asv/Makefile create mode 100644 drivers/power/asv/exynos-asv.c create mode 100644 drivers/power/asv/exynos-asv.h create mode 100644 drivers/power/asv/exynos5250-asv.c create mode 100644 drivers/power/asv/samsung-asv.c create mode 100644 include/linux/power/samsung-asv-driver.h create mode 100644 include/linux/power/samsung-asv.h -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC 2/4] power: asv: Add a common asv driver for exynos SoCs.
This patch adds a common platform driver to register ASV members for exynos SoCs. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/power/asv/Kconfig | 13 +++ drivers/power/asv/Makefile |1 + drivers/power/asv/exynos-asv.c | 72 drivers/power/asv/exynos-asv.h | 21 +++ 4 files changed, 107 insertions(+), 0 deletions(-) create mode 100644 drivers/power/asv/exynos-asv.c create mode 100644 drivers/power/asv/exynos-asv.h diff --git a/drivers/power/asv/Kconfig b/drivers/power/asv/Kconfig index 7cd84bd..6104b09 100644 --- a/drivers/power/asv/Kconfig +++ b/drivers/power/asv/Kconfig @@ -9,3 +9,16 @@ menuconfig POWER_ASV manufacturing process. Say Y here to enable Adaptive Supply voltage support. + +if POWER_ASV + +config POWER_EXYNOS_ASV + bool Adaptive Supply Voltage for Exynos + help + Exynos supports ASV depending upon the ASV group fused on chip. + Users can request ASV specific to a frequency for a particular member + from corresponding DVFS driver. + + Say Y here to enable Exynos Adaptive Voltage Scaling. + +endif diff --git a/drivers/power/asv/Makefile b/drivers/power/asv/Makefile index 62921da..9a94868 100644 --- a/drivers/power/asv/Makefile +++ b/drivers/power/asv/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_POWER_ASV)+= asv.o +obj-$(CONFIG_POWER_EXYNOS_ASV) += exynos-asv.o diff --git a/drivers/power/asv/exynos-asv.c b/drivers/power/asv/exynos-asv.c new file mode 100644 index 000..d3f43a4 --- /dev/null +++ b/drivers/power/asv/exynos-asv.c @@ -0,0 +1,72 @@ +/* Common Exynos ASV(Adaptive Supply Voltage) driver + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include linux/err.h +#include linux/io.h +#include linux/slab.h +#include linux/of_address.h +#include linux/module.h +#include linux/platform_device.h +#include linux/power/asv-driver.h +#include exynos-asv.h + +static int exynos_asv_probe(struct platform_device *pdev) +{ + struct device_node *chip_id; + struct exynos_asv_common *exynos_asv_info; + void __iomem *base; + int ret = 0; + + exynos_asv_info = kzalloc(sizeof(struct exynos_asv_common), GFP_KERNEL); + if (!exynos_asv_info) + return -ENOMEM; + + chip_id = of_find_compatible_node(NULL, NULL, + samsung,exynos4210-chipid); + if (!chip_id) { + pr_err(%s: unable to find chipid\n, __func__); + ret = -ENODEV; + goto err_node; + } + + base = of_iomap(chip_id, 0); + if (!base) { + pr_err(%s: unable to map chip_id register\n, __func__); + ret = -ENOMEM; + goto err_map; + } + + exynos_asv_info-base = base; + + /* call SoC specific intialisation routine */ + + register_asv_member(exynos_asv_info-asv_list, exynos_asv_info-nr_mem); + + iounmap(base); +err_map: + of_node_put(chip_id); +err_node: + kfree(exynos_asv_info); + + return ret; +} + +static struct platform_driver exynos_asv_platdrv = { + .driver = { + .name = exynos-asv, + .owner = THIS_MODULE, + }, + .probe = exynos_asv_probe, +}; +module_platform_driver(exynos_asv_platdrv); + +MODULE_AUTHOR(Yadwinder Singh Braryadi.b...@samsung.com); +MODULE_DESCRIPTION(Common Exynos ASV driver); +MODULE_LICENSE(GPL); diff --git a/drivers/power/asv/exynos-asv.h b/drivers/power/asv/exynos-asv.h new file mode 100644 index 000..89a1ae8 --- /dev/null +++ b/drivers/power/asv/exynos-asv.h @@ -0,0 +1,21 @@ +/* + * Exynos - Adaptive Supply Voltage Driver Header File + * + * copyright (c) 2013 samsung electronics co., ltd. + * http://www.samsung.com/ + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license version 2 as + * published by the free software foundation. +*/ + +#ifndef __EXYNOS_ASV_D_H +#define __EXYNOS_ASV_D_H __FILE__ + +struct exynos_asv_common { + struct asv_info *asv_list; + unsigned int nr_mem; + void __iomem *base; +}; + +#endif /* __EXYNOS_ASV_D_H */ -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC 1/4] power: asv: Add common ASV support for samsung SoCs
This patch introduces a common ASV(Adaptive Supply Voltage) basic framework for samsung SoCs. It provides common APIs (to be called by users to get ASV values or init opp_table) and an interface for SoC specific drivers to register ASV members(instances). Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- Hopefully asv_get_volt() can go out in future, once all users start using OPP library. --- drivers/power/Kconfig|1 + drivers/power/Makefile |1 + drivers/power/asv/Kconfig| 11 ++ drivers/power/asv/Makefile |1 + drivers/power/asv/samsung-asv.c | 175 ++ include/linux/power/samsung-asv-driver.h | 61 +++ include/linux/power/samsung-asv.h| 37 +++ 7 files changed, 287 insertions(+), 0 deletions(-) create mode 100644 drivers/power/asv/Kconfig create mode 100644 drivers/power/asv/Makefile create mode 100644 drivers/power/asv/samsung-asv.c create mode 100644 include/linux/power/samsung-asv-driver.h create mode 100644 include/linux/power/samsung-asv.h diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 7b8979c..2e6b087 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -367,3 +367,4 @@ source drivers/power/reset/Kconfig endif # POWER_SUPPLY source drivers/power/avs/Kconfig +source drivers/power/asv/Kconfig diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 653bf6c..da93c46 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_POWER_AVS)+= avs/ +obj-$(CONFIG_POWER_ASV)+= asv/ obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o obj-$(CONFIG_POWER_RESET) += reset/ diff --git a/drivers/power/asv/Kconfig b/drivers/power/asv/Kconfig new file mode 100644 index 000..7cd84bd --- /dev/null +++ b/drivers/power/asv/Kconfig @@ -0,0 +1,11 @@ +menuconfig POWER_ASV + bool Adaptive Supply Voltage support + help + ASV is a technique used on samsung SoCs, which provides the + recommended supply voltage for some specific parts(like arm, mif etc) + of SoCs which supports dvfs. For a given operating frequency, the + voltage is recommended based on SoCs ASV group. + ASV group info is provided in the chip id info which depends on chip + manufacturing process. + + Say Y here to enable Adaptive Supply voltage support. diff --git a/drivers/power/asv/Makefile b/drivers/power/asv/Makefile new file mode 100644 index 000..62921da --- /dev/null +++ b/drivers/power/asv/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_POWER_ASV)+= asv.o diff --git a/drivers/power/asv/asv.c b/drivers/power/asv/asv.c new file mode 100644 index 000..61f4a83 --- /dev/null +++ b/drivers/power/asv/asv.c @@ -0,0 +1,175 @@ +/* + * ASV(Adaptive Supply Voltage) common core + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include linux/io.h +#include linux/opp.h +#include linux/slab.h +#include linux/device.h +#include linux/power/asv-driver.h + +static LIST_HEAD(asv_list); +static DEFINE_MUTEX(asv_mutex); + +struct asv_member { + struct list_headnode; + struct asv_info *asv_info; +}; + +static void add_asv_member(struct asv_member *asv_mem) +{ + mutex_lock(asv_mutex); + list_add_tail(asv_mem-node, asv_list); + mutex_unlock(asv_mutex); +} + +static struct asv_member *asv_get_mem(enum asv_type_id asv_type) +{ + struct asv_member *asv_mem; + struct asv_info *asv_info; + + list_for_each_entry(asv_mem, asv_list, node) { + asv_info = asv_mem-asv_info; + if (asv_type == asv_info-type) + return asv_mem; + } + + return NULL; +} + +unsigned int asv_get_volt(enum asv_type_id target_type, + unsigned int target_freq) +{ + struct asv_member *asv_mem = asv_get_mem(target_type); + struct asv_freq_table *dvfs_table; + struct asv_info *asv_info; + unsigned int i; + + if (!asv_mem) + return 0; + + asv_info = asv_mem-asv_info; + dvfs_table = asv_info-dvfs_table; + + for (i = 0; i asv_info-nr_dvfs_level; i++) { + if (dvfs_table[i].freq == target_freq) + return dvfs_table[i].volt; + } + + return 0; +} + +int asv_init_opp_table(struct device *dev, enum asv_type_id target_type
[RFC 4/4] arm: exynos5: Register static platform device for ASV.
Since ASV is not a hardware controller so we cann't add device tree node for it. This patch registers a static platform device exynos ASV. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/mach-exynos/mach-exynos5-dt.c |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index f874b77..5ce58e1 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -28,6 +28,7 @@ static void __init exynos5_dt_machine_init(void) struct device_node *i2c_np; const char *i2c_compat = samsung,s3c2440-i2c; unsigned int tmp; + struct platform_device_info devinfo = { .name = exynos-asv, }; /* * Exynos5's legacy i2c controller and new high speed i2c @@ -48,6 +49,8 @@ static void __init exynos5_dt_machine_init(void) } of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + platform_device_register_full(devinfo); } static char const *exynos5_dt_compat[] __initdata = { -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC 3/4] power: asv: Add support for exynos5250
This patch adds basic support (only for ARM ASV) for exynos5250 chips which have fused ASV group. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/power/asv/Makefile |2 +- drivers/power/asv/exynos-asv.c |9 +++ drivers/power/asv/exynos-asv.h |1 + drivers/power/asv/exynos5250-asv.c | 141 4 files changed, 152 insertions(+), 1 deletions(-) create mode 100644 drivers/power/asv/exynos5250-asv.c diff --git a/drivers/power/asv/Makefile b/drivers/power/asv/Makefile index 9a94868..a471c8e 100644 --- a/drivers/power/asv/Makefile +++ b/drivers/power/asv/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_POWER_ASV)+= asv.o -obj-$(CONFIG_POWER_EXYNOS_ASV) += exynos-asv.o +obj-$(CONFIG_POWER_EXYNOS_ASV) += exynos-asv.o exynos5250-asv.o diff --git a/drivers/power/asv/exynos-asv.c b/drivers/power/asv/exynos-asv.c index d3f43a4..7449b55 100644 --- a/drivers/power/asv/exynos-asv.c +++ b/drivers/power/asv/exynos-asv.c @@ -46,9 +46,18 @@ static int exynos_asv_probe(struct platform_device *pdev) exynos_asv_info-base = base; /* call SoC specific intialisation routine */ + if (of_machine_is_compatible(samsung,exynos5250)) { + ret = exynos5250_asv_init(exynos_asv_info); + if (ret) { + pr_err(%s: exynos5250_asv_init failed : %d\n, + __func__, ret); + goto err; + } + } register_asv_member(exynos_asv_info-asv_list, exynos_asv_info-nr_mem); +err: iounmap(base); err_map: of_node_put(chip_id); diff --git a/drivers/power/asv/exynos-asv.h b/drivers/power/asv/exynos-asv.h index 89a1ae8..a31becb 100644 --- a/drivers/power/asv/exynos-asv.h +++ b/drivers/power/asv/exynos-asv.h @@ -18,4 +18,5 @@ struct exynos_asv_common { void __iomem *base; }; +extern int exynos5250_asv_init(struct exynos_asv_common *exynos_info); #endif /* __EXYNOS_ASV_D_H */ diff --git a/drivers/power/asv/exynos5250-asv.c b/drivers/power/asv/exynos5250-asv.c new file mode 100644 index 000..293b3f1 --- /dev/null +++ b/drivers/power/asv/exynos5250-asv.c @@ -0,0 +1,141 @@ +/* exynos5250 - ASV(Adaptive Supply Voltage) + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include linux/err.h +#include linux/io.h +#include linux/slab.h +#include linux/power/asv-driver.h +#include exynos-asv.h + +#define FUSED_SG_OFFSET3 +#define ORIG_SG_OFFSET 17 +#define ORIG_SG_MASK 0xF +#define MOD_SG_OFFSET 21 +#define MOD_SG_MASK0x7 + +#define ARM_LEVEL_NR 16 +#define ARM_GRP_NR 12 + +#define CHIP_ID_OFFSET 0x4 + +struct exynos5250_asv_info { + unsigned int package_id; + /* we may need more info as global data */ +}; + +static struct exynos5250_asv_info asv_group __initdata; + +static unsigned int asv_voltage[ARM_LEVEL_NR][ARM_GRP_NR + 1] __initdata = { + { 170, 130, 1275000, 1275000, 1262500, 125, 1225000, + 1212500, 120, 1187500, 1175000, 115, 1125000 }, /* L0 */ + { 160, 125, 1225000, 1225000, 1212500, 120, 1187500, + 1175000, 1162500, 115, 1137500, 1112500, 110 }, /* L1 */ + { 150, 1225000, 1187500, 1175000, 1162500, 115, 1137500, + 1125000, 1112500, 110, 1087500, 1075000, 1062500 }, /* L2 */ + { 140, 120, 1125000, 1125000, 1125000, 1112500, 110, + 1087500, 1075000, 1062500, 105, 1037500, 1025000 }, /* L3 */ + { 130, 115, 110, 110, 110, 1087500, 1075000, + 1062500, 105, 1037500, 1025000, 1012500, 100 }, /* L4 */ + { 120, 1125000, 1075000, 1075000, 1062500, 105, 1037500, + 1025000, 1012500, 100, 987500, 975000, 975000 }, /* L5 */ + { 110, 110, 105, 105, 1037500, 1025000, 1012500, + 100, 987500, 975000, 962500, 95, 925000 }, /* L6 */ + { 100, 1075000, 1037500, 1037500, 1012500, 100, 987500, + 975000, 962500, 95, 937500, 925000, 912500 }, /* L7 */ + { 90, 105, 1025000, 1012500, 987500, 975000, 962500, + 95, 937500, 925000, 912500, 912500, 90 }, /* L8 */ + { 80, 1025000, 100, 987500, 975000, 962500, 95, + 937500, 925000, 912500, 90, 90, 90 }, /* L9 */ + { 70, 1012500, 975000, 962500, 95, 937500, 925000, + 912500, 90, 90, 90, 90, 90 }, /* L10 */ + { 60, 100, 962500, 95, 937500, 925000, 912500, + 90, 90, 90, 90, 90
Re: [PATCH 10/16] clk: samsung: pll: Add support for rate configuration of PLL45xx
Hi Tomasz, On Tue, Aug 20, 2013 at 11:01 PM, Tomasz Figa t.f...@samsung.com wrote: This patch implements round_rate and set_rate callbacks of PLL45xx driver to allow reconfiguration of PLL at runtime. Signed-off-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Kyungmin Park kyungmin.p...@samsung.com --- drivers/clk/samsung/clk-pll.c | 109 +- drivers/clk/samsung/clk-pll.h | 10 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index b0398d2..cb971cb 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -10,9 +10,12 @@ */ #include linux/errno.h +#include linux/hrtimer.h #include clk.h #include clk-pll.h +#define PLL_TIMEOUT_MS 10 + struct samsung_clk_pll { struct clk_hw hw; void __iomem*lock_reg; @@ -272,13 +275,20 @@ static const struct clk_ops samsung_pll36xx_clk_min_ops = { /* * PLL45xx Clock Type */ +#define PLL4502_LOCK_FACTOR400 +#define PLL4508_LOCK_FACTOR240 #define PLL45XX_MDIV_MASK (0x3FF) #define PLL45XX_PDIV_MASK (0x3F) #define PLL45XX_SDIV_MASK (0x7) +#define PLL45XX_AFC_MASK (0x1F) #define PLL45XX_MDIV_SHIFT (16) #define PLL45XX_PDIV_SHIFT (8) #define PLL45XX_SDIV_SHIFT (0) +#define PLL45XX_AFC_SHIFT (0) + +#define PLL45XX_ENABLE BIT(31) +#define PLL45XX_LOCKED BIT(29) static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -301,8 +311,100 @@ static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1, + const struct samsung_pll_rate_table *rate) +{ + u32 old_mdiv, old_pdiv, old_afc; + + old_mdiv = (pll_con0 PLL45XX_MDIV_SHIFT) PLL45XX_MDIV_MASK; + old_pdiv = (pll_con0 PLL45XX_PDIV_SHIFT) PLL45XX_PDIV_MASK; + old_afc = (pll_con1 PLL45XX_AFC_SHIFT) PLL45XX_AFC_MASK; old_afc doesn't required in this function. + + return (old_mdiv != rate-mdiv || old_pdiv != rate-pdiv); +} + +static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 con0, con1; + ktime_t start; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + con0 = __raw_readl(pll-con_reg); + con1 = __raw_readl(pll-con_reg + 0x4); + + if (!(samsung_pll45xx_mp_change(con0, con1, rate))) { + /* If only s change, change just s value only*/ + con0 = ~(PLL45XX_SDIV_MASK PLL45XX_SDIV_SHIFT); + con0 |= rate-sdiv PLL45XX_SDIV_SHIFT; + __raw_writel(con0, pll-con_reg); + + return 0; + } + + /* Set PLL PMS values. */ + con0 = ~((PLL45XX_MDIV_MASK PLL45XX_MDIV_SHIFT) | + (PLL45XX_PDIV_MASK PLL45XX_PDIV_SHIFT) | + (PLL45XX_SDIV_MASK PLL45XX_SDIV_SHIFT)); + con0 |= (rate-mdiv PLL45XX_MDIV_SHIFT) | + (rate-pdiv PLL45XX_PDIV_SHIFT) | + (rate-sdiv PLL45XX_SDIV_SHIFT); + + /* Set PLL AFC value. */ + con1 = __raw_readl(pll-con_reg + 0x4); + con1 = ~(PLL45XX_AFC_MASK PLL45XX_AFC_SHIFT); + con1 |= (rate-afc PLL45XX_AFC_SHIFT); + Do we need to take care of AFC_ENB also, if we are using AFC ? Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 12/16] clk: samsung: pll: Add support for rate configuration of PLL46xx
+ con0 |= (rate-mdiv PLL46XX_MDIV_SHIFT) | + (rate-pdiv PLL46XX_PDIV_SHIFT) | + (rate-sdiv PLL46XX_SDIV_SHIFT) | + (rate-vsel PLL46XX_VSEL_SHIFT); + + /* Set PLL AFC, MFR and MRR values. */ This comments seems to be miss match with below code. + con1 = __raw_readl(pll-con_reg + 0x4); + con1 = ~((PLL46XX_KDIV_MASK PLL46XX_KDIV_SHIFT) | + (PLL46XX_MFR_MASK PLL46XX_MFR_SHIFT) | + (PLL46XX_MRR_MASK PLL46XX_MRR_SHIFT)); + con1 |= (rate-kdiv PLL46XX_KDIV_SHIFT) | + (rate-mfr PLL46XX_MFR_SHIFT) | + (rate-mrr PLL46XX_MRR_SHIFT); + snip --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -51,6 +51,28 @@ enum samsung_pll_type { .afc= (_afc), \ } +#define PLL_4600_RATE(_rate, _m, _p, _s, _k, _vsel)\ + { \ + .rate = (_rate),\ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + .vsel = (_vsel),\ + } + +#define PLL_4650_RATE(_rate, _m, _p, _s, _k, _mfr, _mrr, _vsel)\ + { \ + .rate = (_rate),\ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + .mfr= (_mfr), \ + .mrr= (_mrr), \ + .vsel = (_vsel),\ + } + /* NOTE: Rate table should be kept sorted in descending order. */ struct samsung_pll_rate_table { @@ -60,6 +82,9 @@ struct samsung_pll_rate_table { unsigned int sdiv; unsigned int kdiv; unsigned int afc; + unsigned int mfr; + unsigned int mrr; + unsigned int vsel; }; This struct seems to be expanding too much. Can we re-think on options for using bit map same as register definition? It can reduce code in set_rate also little bit. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 14/16] clk: samsung: exynos4: Register PLL rate tables for Exynos4210
On Tue, Aug 20, 2013 at 11:01 PM, Tomasz Figa t.f...@samsung.com wrote: This patch adds rate tables for PLLs that can be reconfigured at runtime for Exynos4210 SoCs. Provided tables contain PLL coefficients for input clock of 24 MHz and so are registered only in this case. MPLL does not need runtime reconfiguration and so table for it is not provided. Signed-off-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Kyungmin Park kyungmin.p...@samsung.com --- drivers/clk/samsung/clk-exynos4.c | 45 +++ 1 file changed, 45 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 34474ce..e18cfae 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -992,6 +992,40 @@ static struct of_device_id ext_clk_match[] __initdata = { {}, }; +/* PLLs PMS values */ +static struct samsung_pll_rate_table exynos4210_apll_rates[] = { + PLL_45XX_RATE(12, 150, 3, 1, 28), All these tables in this patch as well as next patch can be __initdata Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 12/16] clk: samsung: pll: Add support for rate configuration of PLL46xx
snip --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -51,6 +51,28 @@ enum samsung_pll_type { .afc= (_afc), \ } +#define PLL_4600_RATE(_rate, _m, _p, _s, _k, _vsel)\ + { \ + .rate = (_rate),\ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + .vsel = (_vsel),\ + } + +#define PLL_4650_RATE(_rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ + { \ + .rate = (_rate),\ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + .mfr = (_mfr), \ + .mrr= (_mrr), \ + .vsel = (_vsel),\ + } + /* NOTE: Rate table should be kept sorted in descending order. */ struct samsung_pll_rate_table { @@ -60,6 +82,9 @@ struct samsung_pll_rate_table { unsigned int sdiv; unsigned int kdiv; unsigned int afc; + unsigned int mfr; + unsigned int mrr; + unsigned int vsel; }; This struct seems to be expanding too much. I don't think it's a problem. How many bytes such tables can occupy in a system? no doubt comparing with memory size its negligible.. but comparing only struct size and coding lines it seems costlier :) . Can we re-think on options for using bit map same as register definition? It can reduce code in set_rate also little bit. IMHO it is more clear what the code does when accessing a single coefficient at once. In addition you still would need to preserve bitfields that are not changed by the driver Sorry, I can't see any such problem, it will OR only the required bits. and also unpack some of the coefficients anyway, like pdiv that is used to calculate lock time. Agree, but cases of unpacking will always be less than cases of shifting and packing. Anyways, its only MHO :). Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 09/16] clk: samsung: pll: Use new registration method for PLL45xx
}; +static struct __initdata samsung_pll_clock exynos4210_plls[nr_plls] = { NIT: __initdata should be at last. + [apll] = PLL_A(pll_4508, fout_apll, fout_apll, fin_pll, APLL_LOCK, + APLL_CON0, fout_apll, NULL), + [mpll] = PLL_A(pll_4508, fout_mpll, fout_mpll, fin_pll, + E4210_MPLL_LOCK, E4210_MPLL_CON0, fout_mpll, NULL), +}; + static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = { [apll] = PLL(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, NULL), @@ -1004,7 +1012,7 @@ static void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom) { - struct clk *apll, *mpll, *epll, *vpll; + struct clk *epll, *vpll; reg_base = of_iomap(np, 0); if (!reg_base) @@ -1026,17 +1034,13 @@ static void __init exynos4_clk_init(struct device_node *np, exynos4_clk_register_finpll(xom); if (exynos4_soc == EXYNOS4210) { - apll = samsung_clk_register_pll45xx(fout_apll, fin_pll, - reg_base + APLL_CON0, pll_4508); - mpll = samsung_clk_register_pll45xx(fout_mpll, fin_pll, - reg_base + E4210_MPLL_CON0, pll_4508); + samsung_clk_register_pll(exynos4210_plls, + ARRAY_SIZE(exynos4210_plls), reg_base); epll = samsung_clk_register_pll46xx(fout_epll, fin_pll, reg_base + EPLL_CON0, pll_4600); vpll = samsung_clk_register_pll46xx(fout_vpll, mout_vpllsrc, reg_base + VPLL_CON0, pll_4650c); - samsung_clk_add_lookup(apll, fout_apll); - samsung_clk_add_lookup(mpll, fout_mpll); samsung_clk_add_lookup(epll, fout_epll); samsung_clk_add_lookup(vpll, fout_vpll); } else { diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 0775554..b0398d2 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -280,18 +280,10 @@ static const struct clk_ops samsung_pll36xx_clk_min_ops = { #define PLL45XX_PDIV_SHIFT (8) #define PLL45XX_SDIV_SHIFT (0) -struct samsung_clk_pll45xx { - struct clk_hw hw; - enum pll45xx_type type; - const void __iomem *con_reg; -}; - -#define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw) - static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, pll_con; u64 fvco = parent_rate; @@ -313,43 +305,6 @@ static const struct clk_ops samsung_pll45xx_clk_ops = { .recalc_rate = samsung_pll45xx_recalc_rate, }; -struct clk * __init samsung_clk_register_pll45xx(const char *name, - const char *pname, const void __iomem *con_reg, - enum pll45xx_type type) -{ - struct samsung_clk_pll45xx *pll; - struct clk *clk; - struct clk_init_data init; - - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) { - pr_err(%s: could not allocate pll clk %s\n, __func__, name); - return NULL; - } - - init.name = name; - init.ops = samsung_pll45xx_clk_ops; - init.flags = CLK_GET_RATE_NOCACHE; - init.parent_names = pname; - init.num_parents = 1; - - pll-hw.init = init; - pll-con_reg = con_reg; - pll-type = type; - - clk = clk_register(NULL, pll-hw); - if (IS_ERR(clk)) { - pr_err(%s: failed to register pll clock %s\n, __func__, - name); - kfree(pll); - } - - if (clk_register_clkdev(clk, name, NULL)) - pr_err(%s: failed to register lookup for %s, __func__, name); - - return clk; -} - /* * PLL46xx Clock Type */ @@ -724,6 +679,11 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, else init.ops = samsung_pll35xx_clk_ops; break; + case pll_4500: + case pll_4502: + case pll_4508: + init.ops = samsung_pll45xx_clk_ops; + break; /* clk_ops for 36xx and 2650 are similar */ case pll_36xx: case pll_2650: diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 2f70e88..f3faf24 100644 --- a/drivers/clk/samsung/clk-pll.h +++
Re: [PATCH] ARM: EXYNOS: Fix low level debug support
On Mon, Jul 22, 2013 at 6:37 PM, Tomasz Figa t.f...@samsung.com wrote: On Monday 22 of July 2013 06:23:06 Thomas Abraham wrote: On 13 July 2013 04:57, Yadwinder Singh Brar yadi.b...@samsung.com wrote: Presently, using exynos_defconfig with CONFIG_DEBUG_LL and CONFIG_EARLY_PRINTK on, kernel is not booting, we are getting following: [0.00] [ cut here ] [0.00] kernel BUG at mm/vmalloc.c:1134! [0.00] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [0.00] Modules linked in: [0.00] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc1 #633 [0.00] task: c052ec48 ti: c0524000 task.ti: c0524000 [0.00] PC is at vm_area_add_early+0x54/0x94 [0.00] LR is at add_static_vm_early+0xc/0x60 Its because iotable_init tries to map UART again which is already mapped by debug_ll_io_init() call in exynos_init_io() within same virtal address range as requested later. debug_ll_io_init ioremaps debug uart address space with 4KB size whereas the exynos_init_io() function ioremaps a single 512KB memory size for all the four uart ports which envelops the mapping created by debug_ll_io_init. This is caught as a kernel bug. Right. This issue seems to be occured after : commit ee4de5d99aeac44f4507b7538b2b3faedc5205b9 ARM: 7781/1: mmu: Add debug_ll_io_init() mappings to early mappings This patch moves S3C_UART iodesc(in iodesc_list) inside CONFIG_DEBUG_LL check. Instead of moving, all the such iodesc entries for UART controller can be removed for all Samsung SoC's now since the Samsung uart driver does a ioremap during probe and any needed iomapping for earlyprintk is handled by debug_ll_io_init(). Yes. This mapping should not be here, but... If you look at plat-samsung/pm.c, there is a debugging code that relies on presence of this mapping. Thanks for pointing this, I completely missed it. So until this gets fixed/removed (I'm working on it right now), I'd suggest keeping Yadwinder's solution. But that debugging code is under CONFIG_SAMSUNG_PM_DEBUG and SAMSUNG_PM_DEBUG selects DEBUG_LL also. So the problem you stated below will their always when ever it will enter that code The only problem is that the code in pm.c expects _all_ UARTs to be mapped (see s3c_pm_resture_uarts() and co.), so in case of DEBUG_LL enabled, something must be done ensure that rest of the ports are mapped. how about fixing this problem with something like below: saving only mapped/configured UART's registers. 8 diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index ea36136..34a7371 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -102,10 +102,8 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_u static void s3c_pm_save_uarts(void) { struct pm_uart_save *save = uart_save; - unsigned int uart; - for (uart = 0; uart CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) - s3c_pm_save_uart(uart, save); + s3c_pm_save_uart(CONFIG_DEBUG_S3C_UART, save); } static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) 8-- I'm going to completely rework Samsung PM code in some time, so this problem will go away, but this must be fixed in 3.11. Yes, it will be helpful if we have it fixed. Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[v2 PATCH 0/2] EXYNOS: Fix low level debug support
Presently, using exynos_defconfig with CONFIG_DEBUG_LL and CONFIG_EARLY_PRINTK on, kernel is not booting, we are getting following: [0.00] [ cut here ] [0.00] kernel BUG at mm/vmalloc.c:1134! [0.00] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [0.00] Modules linked in: [0.00] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc1 #633 [0.00] task: c052ec48 ti: c0524000 task.ti: c0524000 [0.00] PC is at vm_area_add_early+0x54/0x94 [0.00] LR is at add_static_vm_early+0xc/0x60 Its because exynos[4/5]_map_io() function ioremaps a single 512KB memory size for all the four uart ports which envelopes the mapping created by debug_ll_io_init(), called earlier in exynos_init_io(). This issue seems to be occured after : commit ee4de5d99aeac44f4507b7538b2b3faedc5205b9 ARM: 7781/1: mmu: Add debug_ll_io_init() mappings to early mappings This series removes static iodesc entries for UART controller for all Samsung SoC's and modifies pm debug code to save/restore only the selected debug uart registers. changes since v1: - removed uart iodesc entires instead of just moving inside CONFIG_DEBUG_LL check, as suggested by Thomas Abraham. - Fixed the possible issue after removing uart entries pointed by Tomasz Figa. Tested doing suspend/resume on smdk5250. Yadwinder Singh Brar (2): ARM: SAMSUNG: pm: Save/restore only selected uart's registers ARM: EXYNOS: Fix low level debug support arch/arm/mach-exynos/common.c | 26 -- arch/arm/plat-samsung/pm.c| 14 +++--- 2 files changed, 3 insertions(+), 37 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] ARM: EXYNOS: Fix low level debug support
Presently, using exynos_defconfig with CONFIG_DEBUG_LL and CONFIG_EARLY_PRIN on, kernel is not booting, we are getting following: [0.00] [ cut here ] [0.00] kernel BUG at mm/vmalloc.c:1134! [0.00] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [0.00] Modules linked in: [0.00] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc1 #633 [0.00] task: c052ec48 ti: c0524000 task.ti: c0524000 [0.00] PC is at vm_area_add_early+0x54/0x94 [0.00] LR is at add_static_vm_early+0xc/0x60 Its because exynos[4/5]_map_io() function ioremaps a single 512KB memory size for all the four uart ports which envelopes the mapping created by debug_ll_io_init(), called earlier in exynos_init_io(). This patch removes iodesc entries for UART controller for all Samsung SoC's, since now the Samsung uart driver does a ioremap during probe and any needed iomapping for earlyprintk will be handled by debug_ll_io_init(). Tested on smdk4412 and smdk5250. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/mach-exynos/common.c | 26 -- 1 files changed, 0 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 164685b..ba95e5d 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -58,7 +58,6 @@ static const char name_exynos5440[] = EXYNOS5440; static void exynos4_map_io(void); static void exynos5_map_io(void); -static void exynos5440_map_io(void); static int exynos_init(void); static struct cpu_table cpu_ids[] __initdata = { @@ -95,7 +94,6 @@ static struct cpu_table cpu_ids[] __initdata = { }, { .idcode = EXYNOS5440_SOC_ID, .idmask = EXYNOS5_SOC_MASK, - .map_io = exynos5440_map_io, .init = exynos_init, .name = name_exynos5440, }, @@ -150,11 +148,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_64K, .type = MT_DEVICE, }, { - .virtual= (unsigned long)S3C_VA_UART, - .pfn= __phys_to_pfn(EXYNOS4_PA_UART), - .length = SZ_512K, - .type = MT_DEVICE, - }, { .virtual= (unsigned long)S5P_VA_CMU, .pfn= __phys_to_pfn(EXYNOS4_PA_CMU), .length = SZ_128K, @@ -268,20 +261,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { .pfn= __phys_to_pfn(EXYNOS5_PA_PMU), .length = SZ_64K, .type = MT_DEVICE, - }, { - .virtual= (unsigned long)S3C_VA_UART, - .pfn= __phys_to_pfn(EXYNOS5_PA_UART), - .length = SZ_512K, - .type = MT_DEVICE, - }, -}; - -static struct map_desc exynos5440_iodesc0[] __initdata = { - { - .virtual= (unsigned long)S3C_VA_UART, - .pfn= __phys_to_pfn(EXYNOS5440_PA_UART0), - .length = SZ_512K, - .type = MT_DEVICE, }, }; @@ -388,11 +367,6 @@ static void __init exynos5_map_io(void) iotable_init(exynos5250_iodesc, ARRAY_SIZE(exynos5250_iodesc)); } -static void __init exynos5440_map_io(void) -{ - iotable_init(exynos5440_iodesc0, ARRAY_SIZE(exynos5440_iodesc0)); -} - void __init exynos_init_time(void) { of_clk_init(NULL); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] ARM: SAMSUNG: pm: Save/restore only selected uart's registers
Basically this code gets executed only during debugging i.e when DEBUG_LL SAMSUNG_PM_DEBUG is on, so required only for UART used for debugging. Since we are removing static iodesc entries for UARTs, so now only the selected (CONFIG_DEBUG_S3C_UART) UART will be ioremapped by the debug_ll_io_init() for DEBUG_LL, so save/restore uart registers only for selected uart. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/plat-samsung/pm.c | 14 +++--- 1 files changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index ea36136..d0c2301 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -80,7 +80,7 @@ unsigned char pm_uart_udivslot; #ifdef CONFIG_SAMSUNG_PM_DEBUG -static struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS]; +static struct pm_uart_save uart_save; static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) { @@ -101,11 +101,7 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) static void s3c_pm_save_uarts(void) { - struct pm_uart_save *save = uart_save; - unsigned int uart; - - for (uart = 0; uart CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) - s3c_pm_save_uart(uart, save); + s3c_pm_save_uart(CONFIG_DEBUG_S3C_UART, uart_save); } static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) @@ -126,11 +122,7 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) static void s3c_pm_restore_uarts(void) { - struct pm_uart_save *save = uart_save; - unsigned int uart; - - for (uart = 0; uart CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) - s3c_pm_restore_uart(uart, save); + s3c_pm_restore_uart(CONFIG_DEBUG_S3C_UART, uart_save); } #else static void s3c_pm_save_uarts(void) { } -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] ARM: EXYNOS: Fix low level debug support
Presently, using exynos_defconfig with CONFIG_DEBUG_LL and CONFIG_EARLY_PRINTK on, kernel is not booting, we are getting following: [0.00] [ cut here ] [0.00] kernel BUG at mm/vmalloc.c:1134! [0.00] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [0.00] Modules linked in: [0.00] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc1 #633 [0.00] task: c052ec48 ti: c0524000 task.ti: c0524000 [0.00] PC is at vm_area_add_early+0x54/0x94 [0.00] LR is at add_static_vm_early+0xc/0x60 Its because iotable_init tries to map UART again which is already mapped by debug_ll_io_init() call in exynos_init_io() within same virtal address range as requested later. This issue seems to be occured after : commit ee4de5d99aeac44f4507b7538b2b3faedc5205b9 ARM: 7781/1: mmu: Add debug_ll_io_init() mappings to early mappings This patch moves S3C_UART iodesc(in iodesc_list) inside CONFIG_DEBUG_LL check. Tested on 4412 and 5250 smdks. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/mach-exynos/common.c | 20 ++-- 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 164685b..7f0591f 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -150,11 +150,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_64K, .type = MT_DEVICE, }, { - .virtual= (unsigned long)S3C_VA_UART, - .pfn= __phys_to_pfn(EXYNOS4_PA_UART), - .length = SZ_512K, - .type = MT_DEVICE, - }, { .virtual= (unsigned long)S5P_VA_CMU, .pfn= __phys_to_pfn(EXYNOS4_PA_CMU), .length = SZ_128K, @@ -185,6 +180,14 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, +#ifndef CONFIG_DEBUG_LL + { + .virtual= (unsigned long)S3C_VA_UART, + .pfn= __phys_to_pfn(EXYNOS4_PA_UART), + .length = SZ_512K, + .type = MT_DEVICE, + }, +#endif }; static struct map_desc exynos4_iodesc0[] __initdata = { @@ -268,21 +271,26 @@ static struct map_desc exynos5_iodesc[] __initdata = { .pfn= __phys_to_pfn(EXYNOS5_PA_PMU), .length = SZ_64K, .type = MT_DEVICE, - }, { + }, +#ifndef CONFIG_DEBUG_LL + { .virtual= (unsigned long)S3C_VA_UART, .pfn= __phys_to_pfn(EXYNOS5_PA_UART), .length = SZ_512K, .type = MT_DEVICE, }, +#endif }; static struct map_desc exynos5440_iodesc0[] __initdata = { +#ifndef CONFIG_DEBUG_LL { .virtual= (unsigned long)S3C_VA_UART, .pfn= __phys_to_pfn(EXYNOS5440_PA_UART0), .length = SZ_512K, .type = MT_DEVICE, }, +#endif }; void exynos4_restart(enum reboot_mode mode, const char *cmd) -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ARM: EXYNOS: Fix low level debug support
Hi Thomas, On Mon, Jul 22, 2013 at 4:53 PM, Thomas Abraham thomas.abra...@linaro.org wrote: On 13 July 2013 04:57, Yadwinder Singh Brar yadi.b...@samsung.com wrote: Presently, using exynos_defconfig with CONFIG_DEBUG_LL and CONFIG_EARLY_PRINTK on, kernel is not booting, we are getting following: [0.00] [ cut here ] [0.00] kernel BUG at mm/vmalloc.c:1134! [0.00] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [0.00] Modules linked in: [0.00] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc1 #633 [0.00] task: c052ec48 ti: c0524000 task.ti: c0524000 [0.00] PC is at vm_area_add_early+0x54/0x94 [0.00] LR is at add_static_vm_early+0xc/0x60 Its because iotable_init tries to map UART again which is already mapped by debug_ll_io_init() call in exynos_init_io() within same virtal address range as requested later. debug_ll_io_init ioremaps debug uart address space with 4KB size whereas the exynos_init_io() function ioremaps a single 512KB memory size for all the four uart ports which envelops the mapping created by debug_ll_io_init. This is caught as a kernel bug. Exactly ! This issue seems to be occured after : commit ee4de5d99aeac44f4507b7538b2b3faedc5205b9 ARM: 7781/1: mmu: Add debug_ll_io_init() mappings to early mappings This patch moves S3C_UART iodesc(in iodesc_list) inside CONFIG_DEBUG_LL check. Instead of moving, all the such iodesc entries for UART controller can be removed for all Samsung SoC's now since the Samsung uart driver does a ioremap during probe and any needed iomapping for earlyprintk is handled by debug_ll_io_init(). Ok, will do it. TBH I was not sure about removing completely. Thanks for review. Regards, Yadwinder Tested on 4412 and 5250 smdks. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- arch/arm/mach-exynos/common.c | 20 ++-- 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 164685b..7f0591f 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -150,11 +150,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_64K, .type = MT_DEVICE, }, { - .virtual= (unsigned long)S3C_VA_UART, - .pfn= __phys_to_pfn(EXYNOS4_PA_UART), - .length = SZ_512K, - .type = MT_DEVICE, - }, { .virtual= (unsigned long)S5P_VA_CMU, .pfn= __phys_to_pfn(EXYNOS4_PA_CMU), .length = SZ_128K, @@ -185,6 +180,14 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, +#ifndef CONFIG_DEBUG_LL + { + .virtual= (unsigned long)S3C_VA_UART, + .pfn= __phys_to_pfn(EXYNOS4_PA_UART), + .length = SZ_512K, + .type = MT_DEVICE, + }, +#endif }; static struct map_desc exynos4_iodesc0[] __initdata = { @@ -268,21 +271,26 @@ static struct map_desc exynos5_iodesc[] __initdata = { .pfn= __phys_to_pfn(EXYNOS5_PA_PMU), .length = SZ_64K, .type = MT_DEVICE, - }, { + }, +#ifndef CONFIG_DEBUG_LL + { .virtual= (unsigned long)S3C_VA_UART, .pfn= __phys_to_pfn(EXYNOS5_PA_UART), .length = SZ_512K, .type = MT_DEVICE, }, +#endif }; static struct map_desc exynos5440_iodesc0[] __initdata = { +#ifndef CONFIG_DEBUG_LL { .virtual= (unsigned long)S3C_VA_UART, .pfn= __phys_to_pfn(EXYNOS5440_PA_UART0), .length = SZ_512K, .type = MT_DEVICE, }, +#endif }; void exynos4_restart(enum reboot_mode mode, const char *cmd) -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/6] clk: samsung: move common plls registration into separate function
Hi Heiko, On Wed, Jul 10, 2013 at 4:27 AM, Heiko Stübner he...@sntech.de wrote: All Samsung PLLs use similar code to register the clocks and clkdev lookups. Therefore move these into a separate function to reduce code duplication. Suggested-by: Russell King li...@arm.linux.org.uk Signed-off-by: Heiko Stuebner he...@sntech.de --- I have posted patch for adding common pll registration function which some how missed to get merged. I hope will get merged after rc1. Please give a look at that : http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg19543.html Regards, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 04/11] clk: samsung: Migrate exynos4 to use common samsung_clk_register_pll()
This patch migrates exynos4 pll registeration to use common samsung_clk_register_pll() by intialising table of PLLs. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-exynos4.c | 40 - 1 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 50af410..f2c2156 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -17,7 +17,6 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h /* Exynos4 clock controller register offsets */ #define SRC_LEFTBUS0x4200 @@ -97,12 +96,14 @@ #define GATE_IP_PERIL 0xc950 #define E4210_GATE_IP_PERIR0xc960 #define GATE_BLOCK 0xc970 +#define E4X12_MPLL_LOCK0x10008 #define E4X12_MPLL_CON00x10108 #define SRC_DMC0x10200 #define SRC_MASK_DMC 0x10300 #define DIV_DMC0 0x10500 #define DIV_DMC1 0x10504 #define GATE_IP_DMC0x10900 +#define APLL_LOCK 0x14000 #define APLL_CON0 0x14100 #define E4210_MPLL_CON00x14108 #define SRC_CPU0x14200 @@ -121,6 +122,12 @@ enum exynos4_soc { EXYNOS4X12, }; +/* list of PLLs to be registered */ +enum exynos4_plls { + apll, mpll, epll, vpll, + nr_plls /* number of PLLs */ +}; + /* * Let each supported clock get a unique id. This id is used to lookup the clock * for device tree based platforms. The clocks are categorized into three @@ -990,6 +997,17 @@ static __initdata struct of_device_id ext_clk_match[] = { {}, }; +struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { + [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, + APLL_CON0, fout_apll), + [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, + E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll), + [epll] = PLL_A(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, + EPLL_CON0, fout_epll), + [vpll] = PLL_A(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, + VPLL_CON0, fout_vpll), +}; + /* register exynos4 clocks */ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom) { @@ -1026,22 +1044,16 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so reg_base + EPLL_CON0, pll_4600); vpll = samsung_clk_register_pll46xx(fout_vpll, mout_vpllsrc, reg_base + VPLL_CON0, pll_4650c); + + samsung_clk_add_lookup(apll, fout_apll); + samsung_clk_add_lookup(mpll, fout_mpll); + samsung_clk_add_lookup(epll, fout_epll); + samsung_clk_add_lookup(vpll, fout_vpll); } else { - apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + APLL_CON0); - mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + E4X12_MPLL_CON0); - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + EPLL_CON0); - vpll = samsung_clk_register_pll36xx(fout_vpll, fin_pll, - reg_base + VPLL_CON0); + samsung_clk_register_pll(exynos4_plls, + ARRAY_SIZE(exynos4_plls), reg_base); } - samsung_clk_add_lookup(apll, fout_apll); - samsung_clk_add_lookup(mpll, fout_mpll); - samsung_clk_add_lookup(epll, fout_epll); - samsung_clk_add_lookup(vpll, fout_vpll); - samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks, ARRAY_SIZE(exynos4_fixed_rate_clks)); samsung_clk_register_mux(exynos4_mux_clks, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 08/11] clk: samsung: Add set_rate() clk_ops for PLL35xx
This patch add set_rate() and round_rate() for PLL35xx Reviewed-by: Doug Anderson diand...@chromium.org Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 105 - 1 files changed, 104 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index adc0659..b5c8b15 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -24,16 +24,51 @@ struct samsung_clk_pll { #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) +static const struct samsung_pll_rate_table *samsung_get_pll_settings( + struct samsung_clk_pll *pll, unsigned long rate) +{ + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + for (i = 0; i pll-rate_count; i++) { + if (rate == rate_table[i].rate) + return rate_table[i]; + } + + return NULL; +} + +static long samsung_pll_round_rate(struct clk_hw *hw, + unsigned long drate, unsigned long *prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i pll-rate_count; i++) { + if (drate = rate_table[i].rate) + return rate_table[i].rate; + } + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + /* * PLL35xx Clock Type */ +/* Maximum lock time can be 270 * PDIV cycles */ +#define PLL35XX_LOCK_FACTOR(270) #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) #define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_LOCK_STAT_MASK (0x1) #define PLL35XX_MDIV_SHIFT (16) #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) +#define PLL35XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -53,8 +88,73 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll35xx_mp_change( + const struct samsung_pll_rate_table *rate, u32 pll_con) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_con PLL35XX_MDIV_SHIFT) PLL35XX_MDIV_MASK; + old_pdiv = (pll_con PLL35XX_PDIV_SHIFT) PLL35XX_PDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv); +} + +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 tmp; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + tmp = __raw_readl(pll-con_reg); + + if (!(samsung_pll35xx_mp_change(rate, tmp))) { + /* If only s change, change just s value only*/ + tmp = ~(PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT); + tmp |= rate-sdiv PLL35XX_SDIV_SHIFT; + __raw_writel(tmp, pll-con_reg); + + return 0; + } + + /* Set PLL lock time. */ + __raw_writel(rate-pdiv * PLL35XX_LOCK_FACTOR, + pll-lock_reg); + + /* Change PLL PMS values */ + tmp = ~((PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT) | + (PLL35XX_PDIV_MASK PLL35XX_PDIV_SHIFT) | + (PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT)); + tmp |= (rate-mdiv PLL35XX_MDIV_SHIFT) | + (rate-pdiv PLL35XX_PDIV_SHIFT) | + (rate-sdiv PLL35XX_SDIV_SHIFT); + __raw_writel(tmp, pll-con_reg); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = __raw_readl(pll-con_reg); + } while (!(tmp (PLL35XX_LOCK_STAT_MASK +PLL35XX_LOCK_STAT_SHIFT))); + return 0; +} + static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_pll35xx_set_rate, +}; + +static const struct clk_ops samsung_pll35xx_clk_min_ops = { + .recalc_rate = samsung_pll35xx_recalc_rate, }; /* @@ -384,7 +484,10 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, /* clk_ops for 35xx and 2550 are similar */ case pll_35xx: case pll_2550
[PATCH v7 01/11] clk: samsung: Introduce a common samsung_clk_pll struct
This patch unifies clk strutures used for PLL35xx PLL36xx and adding an extra member lock_reg, so that common code can be factored out. Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 30 -- 1 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 89135f6..8224bde 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -13,6 +13,14 @@ #include clk.h #include clk-pll.h +struct samsung_clk_pll { + struct clk_hw hw; + void __iomem*lock_reg; + void __iomem*con_reg; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) + /* * PLL35xx Clock Type */ @@ -24,17 +32,10 @@ #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) -struct samsung_clk_pll35xx { - struct clk_hw hw; - const void __iomem *con_reg; -}; - -#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw) - static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, pll_con; u64 fvco = parent_rate; @@ -56,7 +57,7 @@ static const struct clk_ops samsung_pll35xx_clk_ops = { struct clk * __init samsung_clk_register_pll35xx(const char *name, const char *pname, const void __iomem *con_reg) { - struct samsung_clk_pll35xx *pll; + struct samsung_clk_pll *pll; struct clk *clk; struct clk_init_data init; @@ -100,17 +101,10 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name, #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) -struct samsung_clk_pll36xx { - struct clk_hw hw; - const void __iomem *con_reg; -}; - -#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw) - static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; u64 fvco = parent_rate; @@ -135,7 +129,7 @@ static const struct clk_ops samsung_pll36xx_clk_ops = { struct clk * __init samsung_clk_register_pll36xx(const char *name, const char *pname, const void __iomem *con_reg) { - struct samsung_clk_pll36xx *pll; + struct samsung_clk_pll *pll; struct clk *clk; struct clk_init_data init; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 11/11] clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC
From: Vikas Sajjan vikas.saj...@linaro.org Adds the EPLL and VPLL freq table for exynos5250 SoC. Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c | 38 ++ drivers/clk/samsung/clk.h|2 + 2 files changed, 40 insertions(+), 0 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 492d119..2aabecb 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -498,6 +498,29 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { GATE(g3d, g3d, aclk_400_g3d, GATE_IP_G3D, 0, 0, 0), }; +static __initdata struct samsung_pll_rate_table vpll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(26600, 266, 3, 3, 0), + /* Not in UM, but need for eDP on snow */ + PLL_36XX_RATE(7050, 94, 2, 4, 0), + { }, +}; + +static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(19200, 64, 2, 2, 0), + PLL_36XX_RATE(180633600, 90, 3, 2, 20762), + PLL_36XX_RATE(18000, 90, 3, 2, 0), + PLL_36XX_RATE(73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(67737600, 90, 2, 4, 20762), + PLL_36XX_RATE(49152000, 98, 3, 4, 19923), + PLL_36XX_RATE(45158400, 90, 3, 4, 20762), + PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + { }, +}; + struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, fout_apll, NULL), @@ -524,6 +547,8 @@ static __initdata struct of_device_id ext_clk_match[] = { static void __init exynos5250_clk_init(struct device_node *np) { void __iomem *reg_base; + struct clk *vpllsrc; + unsigned long fin_pll_rate, mout_vpllsrc_rate = 0; if (np) { reg_base = of_iomap(np, 0); @@ -541,6 +566,19 @@ static void __init exynos5250_clk_init(struct device_node *np) ext_clk_match); samsung_clk_register_mux(exynos5250_pll_pmux_clks, ARRAY_SIZE(exynos5250_pll_pmux_clks)); + + fin_pll_rate = _get_rate(fin_pll); + + if (fin_pll_rate == 24 * MHZ) + exynos5250_plls[epll].rate_table = epll_24mhz_tbl; + + vpllsrc = __clk_lookup(mout_vpllsrc); + if (vpllsrc) + mout_vpllsrc_rate = clk_get_rate(vpllsrc); + + if (mout_vpllsrc_rate == 24 * MHZ) + exynos5250_plls[vpll].rate_table = vpll_24mhz_tbl; + samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls), reg_base); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 4a003d7..d459ef7 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -40,6 +40,8 @@ struct samsung_clock_alias { .alias = a,\ } +#define MHZ (1000 * 1000) + /** * struct samsung_fixed_rate_clock: information about fixed-rate clock * @id: platform specific id of the clock. -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 05/11] clk: samsung: Migrate exynos5420 to use common samsung_clk_register_pll()
This patch migrates exynos5420 pll registeration to use common samsung_clk_register_pll() by intialising table of PLLs and adding PLLs to unique id list of clocks. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-exynos5420.c | 86 +++--- 1 files changed, 58 insertions(+), 28 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 68a96cb..3ea6b4f 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -17,13 +17,30 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h +#define APLL_LOCK 0x0 +#define APLL_CON0 0x100 #define SRC_CPU0x200 #define DIV_CPU0 0x500 #define DIV_CPU1 0x504 #define GATE_BUS_CPU 0x700 #define GATE_SCLK_CPU 0x800 +#define CPLL_LOCK 0x10020 +#define DPLL_LOCK 0x10030 +#define EPLL_LOCK 0x10040 +#define RPLL_LOCK 0x10050 +#define IPLL_LOCK 0x10060 +#define SPLL_LOCK 0x10070 +#define VPLL_LOCK 0x10070 +#define MPLL_LOCK 0x10090 +#define CPLL_CON0 0x10120 +#define DPLL_CON0 0x10128 +#define EPLL_CON0 0x10130 +#define RPLL_CON0 0x10140 +#define IPLL_CON0 0x10150 +#define SPLL_CON0 0x10160 +#define VPLL_CON0 0x10170 +#define MPLL_CON0 0x10180 #define SRC_TOP0 0x10200 #define SRC_TOP1 0x10204 #define SRC_TOP2 0x10208 @@ -75,15 +92,27 @@ #define GATE_TOP_SCLK_MAU 0x1083c #define GATE_TOP_SCLK_FSYS 0x10840 #define GATE_TOP_SCLK_PERIC0x10850 +#define BPLL_LOCK 0x20010 +#define BPLL_CON0 0x20110 #define SRC_CDREX 0x20200 +#define KPLL_LOCK 0x28000 +#define KPLL_CON0 0x28100 #define SRC_KFC0x28200 #define DIV_KFC0 0x28500 +/* list of PLLs */ +enum exynos5420_plls { + apll, cpll, dpll, epll, rpll, ipll, spll, vpll, mpll, + bpll, kpll, + nr_plls /* number of PLLs */ +}; + enum exynos5420_clks { none, /* core clocks */ - fin_pll, + fin_pll, fout_apll, fout_cpll, fout_dpll, fout_epll, fout_rpll, + fout_ipll, fout_spll, fout_vpll, fout_mpll, fout_bpll, fout_kpll, /* gate for special clocks (sclk) */ sclk_uart0 = 128, sclk_uart1, sclk_uart2, sclk_uart3, sclk_mmc0, @@ -698,6 +727,31 @@ struct samsung_gate_clock exynos5420_gate_clks[] __initdata = { GATE(smmu_mscl2, smmu_mscl2, aclk400_mscl, GATE_IP_MSCL, 10, 0, 0), }; +struct __initdata samsung_pll_clock exynos5420_plls[nr_plls] = { + [apll] = PLL(pll_2550, fout_apll, fout_apll, fin_pll, APLL_LOCK, + APLL_CON0), + [cpll] = PLL(pll_2550, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, + MPLL_CON0), + [dpll] = PLL(pll_2550, fout_dpll, fout_dpll, fin_pll, DPLL_LOCK, + DPLL_CON0), + [epll] = PLL(pll_2650, fout_epll, fout_epll, fin_pll, EPLL_LOCK, + EPLL_CON0), + [rpll] = PLL(pll_2650, fout_rpll, fout_rpll, fin_pll, RPLL_LOCK, + RPLL_CON0), + [ipll] = PLL(pll_2550, fout_ipll, fout_ipll, fin_pll, IPLL_LOCK, + IPLL_CON0), + [spll] = PLL(pll_2550, fout_spll, fout_spll, fin_pll, SPLL_LOCK, + SPLL_CON0), + [vpll] = PLL(pll_2550, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, + VPLL_CON0), + [mpll] = PLL(pll_2550, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, + MPLL_CON0), + [bpll] = PLL(pll_2550, fout_bpll, fout_bpll, fin_pll, BPLL_LOCK, + BPLL_CON0), + [kpll] = PLL(pll_2550, fout_kpll, fout_kpll, fin_pll, KPLL_LOCK, + KPLL_CON0), +}; + static __initdata struct of_device_id ext_clk_match[] = { { .compatible = samsung,exynos5420-oscclk, .data = (void *)0, }, { }, @@ -707,8 +761,6 @@ static __initdata struct of_device_id ext_clk_match[] = { void __init exynos5420_clk_init(struct device_node *np) { void __iomem *reg_base; - struct clk *apll, *bpll, *cpll, *dpll, *epll, *ipll, *kpll, *mpll; - struct clk *rpll, *spll, *vpll; if (np) { reg_base = of_iomap(np, 0); @@ -724,30 +776,8 @@ void __init exynos5420_clk_init(struct device_node *np) samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks, ARRAY_SIZE(exynos5420_fixed_rate_ext_clks), ext_clk_match); - - apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + 0x100); - bpll = samsung_clk_register_pll35xx(fout_bpll, fin_pll
[PATCH v7 10/11] clk: samsung: Reorder MUX registration for mout_vpllsrc
From: Vikas Sajjan vikas.saj...@linaro.org While trying to get rate of mout_vpllsrc MUX (parent) for registering the fout_vpll (child), we found get rate was failing. So this patch moves the mout_vpllsrc MUX out of the existing common list and registers the mout_vpllsrc MUX before the PLL registrations. Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 623ae44..492d119 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -233,6 +233,10 @@ static struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initda FFACTOR(none, fout_bplldiv2, fout_bpll, 1, 2, 0), }; +static struct samsung_mux_clock exynos5250_pll_pmux_clks[] __initdata = { + MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), +}; + static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, mout_apll, mout_apll_p, SRC_CPU, 0, 1), MUX(none, mout_cpu, mout_cpu_p, SRC_CPU, 16, 1), @@ -240,7 +244,6 @@ static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, sclk_mpll, mout_mpll_p, SRC_CORE1, 8, 1), MUX(none, mout_bpll_fout, mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1), MUX(none, sclk_bpll, mout_bpll_p, SRC_CDREX, 0, 1), - MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), MUX(none, sclk_vpll, mout_vpll_p, SRC_TOP2, 16, 1), MUX(none, sclk_epll, mout_epll_p, SRC_TOP2, 12, 1), MUX(none, sclk_cpll, mout_cpll_p, SRC_TOP2, 8, 1), @@ -536,6 +539,8 @@ static void __init exynos5250_clk_init(struct device_node *np) samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), ext_clk_match); + samsung_clk_register_mux(exynos5250_pll_pmux_clks, + ARRAY_SIZE(exynos5250_pll_pmux_clks)); samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls), reg_base); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 00/11] Add generic set_rate clk_ops for PLL35xx and PLL36xx for samsung SoCs
This patch series does the following: 1) Unifies the clk strutures and registration function used for PLL35xx PLL36xx, to factor out possible common code. 2) Defines a common rate_table which will contain recommended p, m, s and k values for supported rates that needs to be changed for changing corresponding PLL's rate 3) Adds set_rate() and round_rate() clk_ops for PLL35xx and PLL36xx changes since v6: - Splited the patch adding samsung_clk_register_pll() into definition addition, SoC specific migration and cleanup patches. - Addressed some NIT comments. changes since v5: - Corrected to use rate table as specified in UM for exynos5250 epll. - Took care of exynos5420 as well, as new exynos5420 clk driver came in while rebasing on latest Kgene's for-next. Since we spilted 1st patch into 2 different patches, can we expect reviewed-by again for the same? changes since v4: - Defined common samsung samsung_clk_register_pll() to register a list of PLL and used a struct samsung_pll_clock for passing intialisation data instead of passing as arguments. Now passing LOCK as well as CON0 offset as intialisation data. - Calculated length of rate table while registering PLL instead of getting it as intialisation data. changes since v3: - Used __clk_lookup() instead of adding alias for mout_vpllsrc - Added check for changing only M value in samsung_pll36xx_set_rate() - Modified samsung_pll35xx_mp_change() samsung_pll35xx_set_rate() to improve readabilty. - Made the input rate_table as __init_data which is to be provided while registering PLL and made a copy of that table while registering, so that if multiple tables are their, they can be freed after getting the P, M, S, K setting values from required one. changes since v2: - Added new patch to reorder the MUX registration for mout_vpllsrc MUX before the PLL registrations. And to add the alias for the mout_vpllsrc MUX. - Added a check to confirm parent rate while registrating the PLL rate tables. changes since v1: - removed sorting and bsearch - modified the definition of struct samsung_pll_rate_table - added generic round_rate() - rectified the ops assignment for rate table passed as NULL Is rebased on branch kgene's for-next https://git.kernel.org/cgit/linux/kernel/git/kgene/linux-samsung.git/log/?h=for-next Vikas Sajjan (3): clk: samsung: Add set_rate() clk_ops for PLL36xx clk: samsung: Reorder MUX registration for mout_vpllsrc clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC Yadwinder Singh Brar (8): clk: samsung: Introduce a common samsung_clk_pll struct clk: samsung: Define a common samsung_clk_register_pll() clk: samsung: Migrate exynos5250 to use common samsung_clk_register_pll() clk: samsung: Migrate exynos4 to use common samsung_clk_register_pll() clk: samsung: Migrate exynos5420 to use common samsung_clk_register_pll() clk: samsung: Remove unused pll registeration code for pll35xx and pll36xx clk: samsung: Add support to register rate_table for samsung plls clk: samsung: Add set_rate() clk_ops for PLL35xx drivers/clk/samsung/clk-exynos4.c| 40 +++-- drivers/clk/samsung/clk-exynos5250.c | 101 +-- drivers/clk/samsung/clk-exynos5420.c | 86 ++--- drivers/clk/samsung/clk-pll.c| 339 ++ drivers/clk/samsung/clk-pll.h| 38 - drivers/clk/samsung/clk.h| 53 ++ 6 files changed, 519 insertions(+), 138 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 09/11] clk: samsung: Add set_rate() clk_ops for PLL36xx
From: Vikas Sajjan vikas.saj...@linaro.org This patch adds set_rate and round_rate clk_ops for PLL36xx Reviewed-by: Tomasz Figa t.f...@samsung.com Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-pll.c | 79 - 1 files changed, 78 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index b5c8b15..66cb1cb 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -160,6 +160,8 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = { /* * PLL36xx Clock Type */ +/* Maximum lock time can be 3000 * PDIV cycles */ +#define PLL36XX_LOCK_FACTOR(3000) #define PLL36XX_KDIV_MASK (0x) #define PLL36XX_MDIV_MASK (0x1FF) @@ -168,6 +170,8 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = { #define PLL36XX_MDIV_SHIFT (16) #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) +#define PLL36XX_KDIV_SHIFT (0) +#define PLL36XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -190,8 +194,78 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll36xx_mpk_change( + const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_con0 PLL36XX_MDIV_SHIFT) PLL36XX_MDIV_MASK; + old_pdiv = (pll_con0 PLL36XX_PDIV_SHIFT) PLL36XX_PDIV_MASK; + old_kdiv = (pll_con1 PLL36XX_KDIV_SHIFT) PLL36XX_KDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv || + rate-kdiv != old_kdiv); +} + +static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 tmp, pll_con0, pll_con1; + const struct samsung_pll_rate_table *rate; + + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + pll_con0 = __raw_readl(pll-con_reg); + pll_con1 = __raw_readl(pll-con_reg + 4); + + if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) { + /* If only s change, change just s value only*/ + pll_con0 = ~(PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT); + pll_con0 |= (rate-sdiv PLL36XX_SDIV_SHIFT); + __raw_writel(pll_con0, pll-con_reg); + + return 0; + } + + /* Set PLL lock time. */ + __raw_writel(rate-pdiv * PLL36XX_LOCK_FACTOR, pll-lock_reg); + +/* Change PLL PMS values */ + pll_con0 = ~((PLL36XX_MDIV_MASK PLL36XX_MDIV_SHIFT) | + (PLL36XX_PDIV_MASK PLL36XX_PDIV_SHIFT) | + (PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT)); + pll_con0 |= (rate-mdiv PLL36XX_MDIV_SHIFT) | + (rate-pdiv PLL36XX_PDIV_SHIFT) | + (rate-sdiv PLL36XX_SDIV_SHIFT); + __raw_writel(pll_con0, pll-con_reg); + + pll_con1 = ~(PLL36XX_KDIV_MASK PLL36XX_KDIV_SHIFT); + pll_con1 |= rate-kdiv PLL36XX_KDIV_SHIFT; + __raw_writel(pll_con1, pll-con_reg + 4); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = __raw_readl(pll-con_reg); + } while (!(tmp (1 PLL36XX_LOCK_STAT_SHIFT))); + + return 0; +} + static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, + .set_rate = samsung_pll36xx_set_rate, + .round_rate = samsung_pll_round_rate, +}; + +static const struct clk_ops samsung_pll36xx_clk_min_ops = { + .recalc_rate = samsung_pll36xx_recalc_rate, }; /* @@ -492,7 +566,10 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk, /* clk_ops for 36xx and 2650 are similar */ case pll_36xx: case pll_2650: - init.ops = samsung_pll36xx_clk_ops; + if (!pll-rate_table) + init.ops = samsung_pll36xx_clk_min_ops; + else + init.ops = samsung_pll36xx_clk_ops; break; default: pr_warn(%s: Unknown pll type for pll clk %s\n, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 06/11] clk: samsung: Remove unused pll registeration code for pll35xx and pll36xx
This patch removes samsung_clk_register_pll35xx() and samsung_clk_register_pll36xx() registaration functions as users migrated to new samsung_clk_register_pll(). Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 70 - drivers/clk/samsung/clk-pll.h |4 -- 2 files changed, 0 insertions(+), 74 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index f20af69..7d5bea8 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -55,41 +55,6 @@ static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, }; -struct clk * __init samsung_clk_register_pll35xx(const char *name, - const char *pname, const void __iomem *con_reg) -{ - struct samsung_clk_pll *pll; - struct clk *clk; - struct clk_init_data init; - - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) { - pr_err(%s: could not allocate pll clk %s\n, __func__, name); - return NULL; - } - - init.name = name; - init.ops = samsung_pll35xx_clk_ops; - init.flags = CLK_GET_RATE_NOCACHE; - init.parent_names = pname; - init.num_parents = 1; - - pll-hw.init = init; - pll-con_reg = con_reg; - - clk = clk_register(NULL, pll-hw); - if (IS_ERR(clk)) { - pr_err(%s: failed to register pll clock %s\n, __func__, - name); - kfree(pll); - } - - if (clk_register_clkdev(clk, name, NULL)) - pr_err(%s: failed to register lookup for %s, __func__, name); - - return clk; -} - /* * PLL36xx Clock Type */ @@ -127,41 +92,6 @@ static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, }; -struct clk * __init samsung_clk_register_pll36xx(const char *name, - const char *pname, const void __iomem *con_reg) -{ - struct samsung_clk_pll *pll; - struct clk *clk; - struct clk_init_data init; - - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) { - pr_err(%s: could not allocate pll clk %s\n, __func__, name); - return NULL; - } - - init.name = name; - init.ops = samsung_pll36xx_clk_ops; - init.flags = CLK_GET_RATE_NOCACHE; - init.parent_names = pname; - init.num_parents = 1; - - pll-hw.init = init; - pll-con_reg = con_reg; - - clk = clk_register(NULL, pll-hw); - if (IS_ERR(clk)) { - pr_err(%s: failed to register pll clock %s\n, __func__, - name); - kfree(pll); - } - - if (clk_register_clkdev(clk, name, NULL)) - pr_err(%s: failed to register lookup for %s, __func__, name); - - return clk; -} - /* * PLL45xx Clock Type */ diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 0d86bf0..1536f27 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -31,10 +31,6 @@ enum pll46xx_type { pll_4650c, }; -extern struct clk * __init samsung_clk_register_pll35xx(const char *name, - const char *pname, const void __iomem *con_reg); -extern struct clk * __init samsung_clk_register_pll36xx(const char *name, - const char *pname, const void __iomem *con_reg); extern struct clk * __init samsung_clk_register_pll45xx(const char *name, const char *pname, const void __iomem *con_reg, enum pll45xx_type type); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7 03/11] clk: samsung: Migrate exynos5250 to use common samsung_clk_register_pll()
This patch migrates exynos5250 pll registeration to use common samsung_clk_register_pll() by intialising table of PLLs and adding PLLs to unique id list of clocks. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-exynos5250.c | 60 +++--- 1 files changed, 41 insertions(+), 19 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index f6e3031..4027c69 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -17,11 +17,22 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h +#define APLL_LOCK 0x0 +#define APLL_CON0 0x100 #define SRC_CPU0x200 #define DIV_CPU0 0x500 +#define MPLL_LOCK 0x4000 +#define MPLL_CON0 0x4100 #define SRC_CORE1 0x4204 +#define CPLL_LOCK 0x10020 +#define EPLL_LOCK 0x10030 +#define VPLL_LOCK 0x10040 +#define GPLL_LOCK 0x10050 +#define CPLL_CON0 0x10120 +#define EPLL_CON0 0x10130 +#define VPLL_CON0 0x10140 +#define GPLL_CON0 0x10150 #define SRC_TOP0 0x10210 #define SRC_TOP1 0x10214 #define SRC_TOP2 0x10218 @@ -61,10 +72,18 @@ #define GATE_IP_FSYS 0x10944 #define GATE_IP_PERIC 0x10950 #define GATE_IP_PERIS 0x10960 +#define BPLL_LOCK 0x20010 +#define BPLL_CON0 0x20110 #define SRC_CDREX 0x20200 #define PLL_DIV2_SEL 0x20a24 #define GATE_IP_DISP1 0x10928 +/* list of PLLs to be registered */ +enum exynos5250_plls { + apll, mpll, cpll, epll, vpll, gpll, bpll, + nr_plls /* number of PLLs */ +}; + /* * Let each supported clock get a unique id. This id is used to lookup the clock * for device tree based platforms. The clocks are categorized into three @@ -81,7 +100,8 @@ enum exynos5250_clks { none, /* core clocks */ - fin_pll, + fin_pll, fout_apll, fout_mpll, fout_bpll, fout_gpll, fout_cpll, + fout_epll, fout_vpll, /* gate for special clocks (sclk) */ sclk_cam_bayer = 128, sclk_cam0, sclk_cam1, sclk_gscl_wa, sclk_gscl_wb, @@ -475,6 +495,23 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { GATE(g3d, g3d, aclk_400_g3d, GATE_IP_G3D, 0, 0, 0), }; +struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { + [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, + APLL_CON0, fout_apll), + [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, + MPLL_CON0, fout_mpll), + [bpll] = PLL(pll_35xx, fout_bpll, fout_bpll, fin_pll, BPLL_LOCK, + BPLL_CON0), + [gpll] = PLL(pll_35xx, fout_gpll, fout_gpll, fin_pll, GPLL_LOCK, + GPLL_CON0), + [cpll] = PLL(pll_35xx, fout_cpll, fout_cpll, fin_pll, CPLL_LOCK, + CPLL_CON0), + [epll] = PLL(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, + EPLL_CON0), + [vpll] = PLL(pll_36xx, fout_vpll, fout_vpll, mout_vpllsrc, + VPLL_LOCK, VPLL_CON0), +}; + static __initdata struct of_device_id ext_clk_match[] = { { .compatible = samsung,clock-xxti, .data = (void *)0, }, { }, @@ -484,7 +521,6 @@ static __initdata struct of_device_id ext_clk_match[] = { static void __init exynos5250_clk_init(struct device_node *np) { void __iomem *reg_base; - struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll; if (np) { reg_base = of_iomap(np, 0); @@ -500,22 +536,8 @@ static void __init exynos5250_clk_init(struct device_node *np) samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), ext_clk_match); - - apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + 0x100); - mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + 0x4100); - bpll = samsung_clk_register_pll35xx(fout_bpll, fin_pll, - reg_base + 0x20110); - gpll = samsung_clk_register_pll35xx(fout_gpll, fin_pll, - reg_base + 0x10150); - cpll = samsung_clk_register_pll35xx(fout_cpll, fin_pll, - reg_base + 0x10120); - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10130); - vpll = samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc, - reg_base + 0x10140); - + samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls
Re: [PATCH v7 00/11] Add generic set_rate clk_ops for PLL35xx and PLL36xx for samsung SoCs
Hi Tomasz, On Thu, Jun 20, 2013 at 3:30 PM, Tomasz Figa t.f...@samsung.com wrote: Hi Yadwinder, Vikas, On Tuesday 11 of June 2013 15:01:05 Yadwinder Singh Brar wrote: This patch series does the following: 1) Unifies the clk strutures and registration function used for PLL35xx PLL36xx, to factor out possible common code. 2) Defines a common rate_table which will contain recommended p, m, s and k values for supported rates that needs to be changed for changing corresponding PLL's rate 3) Adds set_rate() and round_rate() clk_ops for PLL35xx and PLL36xx changes since v6: - Splited the patch adding samsung_clk_register_pll() into definition addition, SoC specific migration and cleanup patches. - Addressed some NIT comments. This version looks good to me. Thanks for your work on improving this series again! Reviewed-by: Tomasz Figa t.f...@samsung.com Thanks for helping to improve this series. Thanks, Yadwinder Best regards, Tomasz changes since v5: - Corrected to use rate table as specified in UM for exynos5250 epll. - Took care of exynos5420 as well, as new exynos5420 clk driver came in while rebasing on latest Kgene's for-next. Since we spilted 1st patch into 2 different patches, can we expect reviewed-by again for the same? changes since v4: - Defined common samsung samsung_clk_register_pll() to register a list of PLL and used a struct samsung_pll_clock for passing intialisation data instead of passing as arguments. Now passing LOCK as well as CON0 offset as intialisation data. - Calculated length of rate table while registering PLL instead of getting it as intialisation data. changes since v3: - Used __clk_lookup() instead of adding alias for mout_vpllsrc - Added check for changing only M value in samsung_pll36xx_set_rate() - Modified samsung_pll35xx_mp_change() samsung_pll35xx_set_rate() to improve readabilty. - Made the input rate_table as __init_data which is to be provided while registering PLL and made a copy of that table while registering, so that if multiple tables are their, they can be freed after getting the P, M, S, K setting values from required one. changes since v2: - Added new patch to reorder the MUX registration for mout_vpllsrc MUX before the PLL registrations. And to add the alias for the mout_vpllsrc MUX. - Added a check to confirm parent rate while registrating the PLL rate tables. changes since v1: - removed sorting and bsearch - modified the definition of struct samsung_pll_rate_table - added generic round_rate() - rectified the ops assignment for rate table passed as NULL Is rebased on branch kgene's for-next https://git.kernel.org/cgit/linux/kernel/git/kgene/linux-samsung.git/log/ ?h=for-next Vikas Sajjan (3): clk: samsung: Add set_rate() clk_ops for PLL36xx clk: samsung: Reorder MUX registration for mout_vpllsrc clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC Yadwinder Singh Brar (8): clk: samsung: Introduce a common samsung_clk_pll struct clk: samsung: Define a common samsung_clk_register_pll() clk: samsung: Migrate exynos5250 to use common samsung_clk_register_pll() clk: samsung: Migrate exynos4 to use common samsung_clk_register_pll() clk: samsung: Migrate exynos5420 to use common samsung_clk_register_pll() clk: samsung: Remove unused pll registeration code for pll35xx and pll36xx clk: samsung: Add support to register rate_table for samsung plls clk: samsung: Add set_rate() clk_ops for PLL35xx drivers/clk/samsung/clk-exynos4.c| 40 +++-- drivers/clk/samsung/clk-exynos5250.c | 101 +-- drivers/clk/samsung/clk-exynos5420.c | 86 ++--- drivers/clk/samsung/clk-pll.c| 339 ++ drivers/clk/samsung/clk-pll.h | 38 - drivers/clk/samsung/clk.h| 53 ++ 6 files changed, 519 insertions(+), 138 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 3/7] clk: samsung: Add support to register rate_table for samsung plls
This patch defines a common rate_table which will contain recommended p, m, s, k values for supported rates that needs to be changed for changing corresponding PLL's rate. Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c|8 drivers/clk/samsung/clk-exynos5250.c | 14 +++--- drivers/clk/samsung/clk-exynos5420.c | 22 +++--- drivers/clk/samsung/clk-pll.c| 22 -- drivers/clk/samsung/clk-pll.h| 27 +++ drivers/clk/samsung/clk.h| 14 +- 6 files changed, 78 insertions(+), 29 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index ba25a1b..ceee66c 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -997,13 +997,13 @@ static __initdata struct of_device_id ext_clk_match[] = { struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, - APLL_CON0, fout_apll), + APLL_CON0, fout_apll, NULL), [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, - E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll), + E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll, NULL), [epll] = PLL_A(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, - EPLL_CON0, fout_epll), + EPLL_CON0, fout_epll, NULL), [vpll] = PLL_A(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, - VPLL_CON0, fout_vpll), + VPLL_CON0, fout_vpll, NULL), }; /* register exynos4 clocks */ diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index dc6a700..21f5491 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -492,19 +492,19 @@ static __initdata struct of_device_id ext_clk_match[] = { struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, - APLL_CON0, fout_apll), + APLL_CON0, fout_apll, NULL), [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, - MPLL_CON0, fout_mpll), + MPLL_CON0, fout_mpll, NULL), [bpll] = PLL(pll_35xx, fout_bpll, fout_bpll, fin_pll, BPLL_LOCK, - BPLL_CON0), + BPLL_CON0, NULL), [gpll] = PLL(pll_35xx, fout_gpll, fout_gpll, fin_pll, GPLL_LOCK, - GPLL_CON0), + GPLL_CON0, NULL), [cpll] = PLL(pll_35xx, fout_cpll, fout_cpll, fin_pll, CPLL_LOCK, - CPLL_CON0), + CPLL_CON0, NULL), [epll] = PLL(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, - EPLL_CON0), + EPLL_CON0, NULL), [vpll] = PLL(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, - VPLL_CON0), + VPLL_CON0, NULL), }; /* register exynox5250 clocks */ diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 3ea6b4f..86dfc64 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -729,27 +729,27 @@ struct samsung_gate_clock exynos5420_gate_clks[] __initdata = { struct __initdata samsung_pll_clock exynos5420_plls[nr_plls] = { [apll] = PLL(pll_2550, fout_apll, fout_apll, fin_pll, APLL_LOCK, - APLL_CON0), + APLL_CON0, NULL), [cpll] = PLL(pll_2550, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, - MPLL_CON0), + MPLL_CON0, NULL), [dpll] = PLL(pll_2550, fout_dpll, fout_dpll, fin_pll, DPLL_LOCK, - DPLL_CON0), + DPLL_CON0, NULL), [epll] = PLL(pll_2650, fout_epll, fout_epll, fin_pll, EPLL_LOCK, - EPLL_CON0), + EPLL_CON0, NULL), [rpll] = PLL(pll_2650, fout_rpll, fout_rpll, fin_pll, RPLL_LOCK, - RPLL_CON0), + RPLL_CON0, NULL), [ipll] = PLL(pll_2550, fout_ipll, fout_ipll, fin_pll, IPLL_LOCK, - IPLL_CON0), + IPLL_CON0, NULL), [spll] = PLL(pll_2550, fout_spll, fout_spll, fin_pll, SPLL_LOCK, - SPLL_CON0), + SPLL_CON0, NULL), [vpll] = PLL(pll_2550, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, - VPLL_CON0), + VPLL_CON0, NULL), [mpll] = PLL(pll_2550, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, - MPLL_CON0), + MPLL_CON0, NULL), [bpll] = PLL(pll_2550, fout_bpll, fout_bpll, fin_pll, BPLL_LOCK, - BPLL_CON0), + BPLL_CON0, NULL), [kpll] = PLL(pll_2550, fout_kpll, fout_kpll, fin_pll, KPLL_LOCK, - KPLL_CON0), + KPLL_CON0, NULL
[PATCH v6 1/7] clk: samsung: Introduce a common samsung_clk_pll struct
This patch unifies clk strutures used for PLL35xx PLL36xx and adding an extra member lock_reg, so that common code can be factored out. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 30 -- 1 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 89135f6..8224bde 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -13,6 +13,14 @@ #include clk.h #include clk-pll.h +struct samsung_clk_pll { + struct clk_hw hw; + void __iomem*lock_reg; + void __iomem*con_reg; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) + /* * PLL35xx Clock Type */ @@ -24,17 +32,10 @@ #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) -struct samsung_clk_pll35xx { - struct clk_hw hw; - const void __iomem *con_reg; -}; - -#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw) - static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, pll_con; u64 fvco = parent_rate; @@ -56,7 +57,7 @@ static const struct clk_ops samsung_pll35xx_clk_ops = { struct clk * __init samsung_clk_register_pll35xx(const char *name, const char *pname, const void __iomem *con_reg) { - struct samsung_clk_pll35xx *pll; + struct samsung_clk_pll *pll; struct clk *clk; struct clk_init_data init; @@ -100,17 +101,10 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name, #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) -struct samsung_clk_pll36xx { - struct clk_hw hw; - const void __iomem *con_reg; -}; - -#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw) - static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; u64 fvco = parent_rate; @@ -135,7 +129,7 @@ static const struct clk_ops samsung_pll36xx_clk_ops = { struct clk * __init samsung_clk_register_pll36xx(const char *name, const char *pname, const void __iomem *con_reg) { - struct samsung_clk_pll36xx *pll; + struct samsung_clk_pll *pll; struct clk *clk; struct clk_init_data init; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 4/7] clk: samsung: Add set_rate() clk_ops for PLL35xx
This patch add set_rate() and round_rate() for PLL35xx Reviewed-by: Doug Anderson diand...@chromium.org Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 105 - 1 files changed, 104 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index b2088dd..e3e7f0c 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -24,16 +24,51 @@ struct samsung_clk_pll { #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) +static const struct samsung_pll_rate_table *samsung_get_pll_settings( + struct samsung_clk_pll *pll, unsigned long rate) +{ + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + for (i = 0; i pll-rate_count; i++) { + if (rate == rate_table[i].rate) + return rate_table[i]; + } + + return NULL; +} + +static long samsung_pll_round_rate(struct clk_hw *hw, + unsigned long drate, unsigned long *prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i pll-rate_count; i++) { + if (drate = rate_table[i].rate) + return rate_table[i].rate; + } + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + /* * PLL35xx Clock Type */ +/* Maximum lock time can be 270 * PDIV cycles */ +#define PLL35XX_LOCK_FACTOR(270) #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) #define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_LOCK_STAT_MASK (0x1) #define PLL35XX_MDIV_SHIFT (16) #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) +#define PLL35XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -53,8 +88,73 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll35xx_mp_change( + const struct samsung_pll_rate_table *rate, u32 pll_con) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_con PLL35XX_MDIV_SHIFT) PLL35XX_MDIV_MASK; + old_pdiv = (pll_con PLL35XX_PDIV_SHIFT) PLL35XX_PDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv); +} + +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 tmp; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + tmp = __raw_readl(pll-con_reg); + + if (!(samsung_pll35xx_mp_change(rate, tmp))) { + /* If only s change, change just s value only*/ + tmp = ~(PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT); + tmp |= rate-sdiv PLL35XX_SDIV_SHIFT; + __raw_writel(tmp, pll-con_reg); + + return 0; + } + + /* Set PLL lock time. */ + __raw_writel(rate-pdiv * PLL35XX_LOCK_FACTOR, + pll-lock_reg); + + /* Change PLL PMS values */ + tmp = ~((PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT) | + (PLL35XX_PDIV_MASK PLL35XX_PDIV_SHIFT) | + (PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT)); + tmp |= (rate-mdiv PLL35XX_MDIV_SHIFT) | + (rate-pdiv PLL35XX_PDIV_SHIFT) | + (rate-sdiv PLL35XX_SDIV_SHIFT); + __raw_writel(tmp, pll-con_reg); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = __raw_readl(pll-con_reg); + } while (!(tmp (PLL35XX_LOCK_STAT_MASK +PLL35XX_LOCK_STAT_SHIFT))); + return 0; +} + static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_pll35xx_set_rate, +}; + +static const struct clk_ops samsung_pll35xx_clk_min_ops = { + .recalc_rate = samsung_pll35xx_recalc_rate, }; /* @@ -386,7 +486,10 @@ void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, /* clk_ops for 35xx and 2550 are similar */ case pll_35xx: case pll_2550
[PATCH v6 2/7] clk: samsung: Define a common samsung_clk_register_pll()
This patch defines a common samsung_clk_register_pll() and its migrating the PLL35xx PLL36xx to use it. Other samsung PLL can also be migrated to it. It also adds exynos5250 exynos5420 PLLs to unique id list of clocks. Since pll2550 pll35xx and pll2650 pll36xx have exactly same clk ops implementation, added pll2550 and pll2650 also. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c| 40 +++ drivers/clk/samsung/clk-exynos5250.c | 60 +++- drivers/clk/samsung/clk-exynos5420.c | 86 +++--- drivers/clk/samsung/clk-pll.c| 132 -- drivers/clk/samsung/clk-pll.h| 11 ++- drivers/clk/samsung/clk.h| 48 6 files changed, 242 insertions(+), 135 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index addc738..ba25a1b 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -17,7 +17,6 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h /* Exynos4 clock controller register offsets */ #define SRC_LEFTBUS0x4200 @@ -97,12 +96,14 @@ #define GATE_IP_PERIL 0xc950 #define E4210_GATE_IP_PERIR0xc960 #define GATE_BLOCK 0xc970 +#define E4X12_MPLL_LOCK0x10008 #define E4X12_MPLL_CON00x10108 #define SRC_DMC0x10200 #define SRC_MASK_DMC 0x10300 #define DIV_DMC0 0x10500 #define DIV_DMC1 0x10504 #define GATE_IP_DMC0x10900 +#define APLL_LOCK 0x14000 #define APLL_CON0 0x14100 #define E4210_MPLL_CON00x14108 #define SRC_CPU0x14200 @@ -121,6 +122,12 @@ enum exynos4_soc { EXYNOS4X12, }; +/* list of PLLs to be registered */ +enum exynos4_plls { + apll, mpll, epll, vpll, + nr_plls /* number of PLLs */ +}; + /* * Let each supported clock get a unique id. This id is used to lookup the clock * for device tree based platforms. The clocks are categorized into three @@ -988,6 +995,17 @@ static __initdata struct of_device_id ext_clk_match[] = { {}, }; +struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { + [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, + APLL_CON0, fout_apll), + [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, + E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll), + [epll] = PLL_A(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, + EPLL_CON0, fout_epll), + [vpll] = PLL_A(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, + VPLL_CON0, fout_vpll), +}; + /* register exynos4 clocks */ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom) { @@ -1024,22 +1042,16 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so reg_base + EPLL_CON0, pll_4600); vpll = samsung_clk_register_pll46xx(fout_vpll, mout_vpllsrc, reg_base + VPLL_CON0, pll_4650c); + + samsung_clk_add_lookup(apll, fout_apll); + samsung_clk_add_lookup(mpll, fout_mpll); + samsung_clk_add_lookup(epll, fout_epll); + samsung_clk_add_lookup(vpll, fout_vpll); } else { - apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + APLL_CON0); - mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + E4X12_MPLL_CON0); - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + EPLL_CON0); - vpll = samsung_clk_register_pll36xx(fout_vpll, fin_pll, - reg_base + VPLL_CON0); + samsung_clk_register_pll(exynos4_plls, + ARRAY_SIZE(exynos4_plls), reg_base); } - samsung_clk_add_lookup(apll, fout_apll); - samsung_clk_add_lookup(mpll, fout_mpll); - samsung_clk_add_lookup(epll, fout_epll); - samsung_clk_add_lookup(vpll, fout_vpll); - samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks, ARRAY_SIZE(exynos4_fixed_rate_clks)); samsung_clk_register_mux(exynos4_mux_clks, diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 7c68850..dc6a700 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -17,11 +17,22 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h +#define APLL_LOCK 0x0 +#define APLL_CON0
[PATCH v6 5/7] clk: samsung: Add set_rate() clk_ops for PLL36xx
From: Vikas Sajjan vikas.saj...@linaro.org This patch adds set_rate and round_rate clk_ops for PLL36xx Reviewed-by: Tomasz Figa t.f...@samsung.com Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-pll.c | 79 - 1 files changed, 78 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index e3e7f0c..2197004 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -160,6 +160,8 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = { /* * PLL36xx Clock Type */ +/* Maximum lock time can be 3000 * PDIV cycles */ +#define PLL36XX_LOCK_FACTOR(3000) #define PLL36XX_KDIV_MASK (0x) #define PLL36XX_MDIV_MASK (0x1FF) @@ -168,6 +170,8 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = { #define PLL36XX_MDIV_SHIFT (16) #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) +#define PLL36XX_KDIV_SHIFT (0) +#define PLL36XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -190,8 +194,78 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll36xx_mpk_change( + const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_con0 PLL36XX_MDIV_SHIFT) PLL36XX_MDIV_MASK; + old_pdiv = (pll_con0 PLL36XX_PDIV_SHIFT) PLL36XX_PDIV_MASK; + old_kdiv = (pll_con1 PLL36XX_KDIV_SHIFT) PLL36XX_KDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv || + rate-kdiv != old_kdiv); +} + +static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 tmp, pll_con0, pll_con1; + const struct samsung_pll_rate_table *rate; + + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + pll_con0 = __raw_readl(pll-con_reg); + pll_con1 = __raw_readl(pll-con_reg + 4); + + if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) { + /* If only s change, change just s value only*/ + pll_con0 = ~(PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT); + pll_con0 |= (rate-sdiv PLL36XX_SDIV_SHIFT); + __raw_writel(pll_con0, pll-con_reg); + + return 0; + } + + /* Set PLL lock time. */ + __raw_writel(rate-pdiv * PLL36XX_LOCK_FACTOR, pll-lock_reg); + +/* Change PLL PMS values */ + pll_con0 = ~((PLL36XX_MDIV_MASK PLL36XX_MDIV_SHIFT) | + (PLL36XX_PDIV_MASK PLL36XX_PDIV_SHIFT) | + (PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT)); + pll_con0 |= (rate-mdiv PLL36XX_MDIV_SHIFT) | + (rate-pdiv PLL36XX_PDIV_SHIFT) | + (rate-sdiv PLL36XX_SDIV_SHIFT); + __raw_writel(pll_con0, pll-con_reg); + + pll_con1 = ~(PLL36XX_KDIV_MASK PLL36XX_KDIV_SHIFT); + pll_con1 |= rate-kdiv PLL36XX_KDIV_SHIFT; + __raw_writel(pll_con1, pll-con_reg + 4); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = __raw_readl(pll-con_reg); + } while (!(tmp (1 PLL36XX_LOCK_STAT_SHIFT))); + + return 0; +} + static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, + .set_rate = samsung_pll36xx_set_rate, + .round_rate = samsung_pll_round_rate, +}; + +static const struct clk_ops samsung_pll36xx_clk_min_ops = { + .recalc_rate = samsung_pll36xx_recalc_rate, }; /* @@ -494,7 +568,10 @@ void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, /* clk_ops for 36xx and 2650 are similar */ case pll_36xx: case pll_2650: - init.ops = samsung_pll36xx_clk_ops; + if (!pll-rate_table) + init.ops = samsung_pll36xx_clk_min_ops; + else + init.ops = samsung_pll36xx_clk_ops; break; default: pr_warn(%s: Unknown pll type for pll clk %s\n, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 6/7] clk: samsung: Reorder MUX registration for mout_vpllsrc
From: Vikas Sajjan vikas.saj...@linaro.org While trying to get rate of mout_vpllsrc MUX (parent) for registering the fout_vpll (child), we found get rate was failing. So this patch moves the mout_vpllsrc MUX out of the existing common list and registers the mout_vpllsrc MUX before the PLL registrations. Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 21f5491..6881810 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -228,6 +228,10 @@ struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = { FFACTOR(none, fout_bplldiv2, fout_bpll, 1, 2, 0), }; +struct samsung_mux_clock exynos5250_pll_pmux_clks[] __initdata = { + MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), +}; + struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, mout_apll, mout_apll_p, SRC_CPU, 0, 1), MUX(none, mout_cpu, mout_cpu_p, SRC_CPU, 16, 1), @@ -235,7 +239,6 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, sclk_mpll, mout_mpll_p, SRC_CORE1, 8, 1), MUX(none, mout_bpll_fout, mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1), MUX(none, sclk_bpll, mout_bpll_p, SRC_CDREX, 0, 1), - MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), MUX(none, sclk_vpll, mout_vpll_p, SRC_TOP2, 16, 1), MUX(none, sclk_epll, mout_epll_p, SRC_TOP2, 12, 1), MUX(none, sclk_cpll, mout_cpll_p, SRC_TOP2, 8, 1), @@ -526,6 +529,8 @@ void __init exynos5250_clk_init(struct device_node *np) samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), ext_clk_match); + samsung_clk_register_mux(exynos5250_pll_pmux_clks, + ARRAY_SIZE(exynos5250_pll_pmux_clks)); samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls), reg_base); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 7/7] clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC
Adds the EPLL and VPLL freq table for exynos5250 SoC. Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c | 42 - drivers/clk/samsung/clk.h|2 + 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 6881810..13e293e 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -493,6 +493,29 @@ static __initdata struct of_device_id ext_clk_match[] = { { }, }; +static __initdata struct samsung_pll_rate_table vpll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(26600, 266, 3, 3, 0), + /* Not in UM, but need for eDP on snow */ + PLL_36XX_RATE(7050, 94, 2, 4, 0), + { }, +}; + +static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(19200, 64, 2, 2, 0), + PLL_36XX_RATE(180633600, 90, 3, 2, 20762), + PLL_36XX_RATE(18000, 90, 3, 2, 0), + PLL_36XX_RATE(73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(67737600, 90, 2, 4, 20762), + PLL_36XX_RATE(49152000, 98, 3, 4, 19923), + PLL_36XX_RATE(45158400, 90, 3, 4, 20762), + PLL_36XX_RATE(32768000, 131, 3, 5, 4719) + { }, +}; + struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, fout_apll, NULL), @@ -506,14 +529,16 @@ struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { CPLL_CON0, NULL), [epll] = PLL(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, EPLL_CON0, NULL), - [vpll] = PLL(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, - VPLL_CON0, NULL), + [vpll] = PLL(pll_36xx, fout_vpll, fout_vpll, mout_vpllsrc, + VPLL_LOCK, VPLL_CON0, NULL), }; /* register exynox5250 clocks */ void __init exynos5250_clk_init(struct device_node *np) { void __iomem *reg_base; + struct clk *vpllsrc; + unsigned long fin_pll_rate, mout_vpllsrc_rate = 0; if (np) { reg_base = of_iomap(np, 0); @@ -531,6 +556,19 @@ void __init exynos5250_clk_init(struct device_node *np) ext_clk_match); samsung_clk_register_mux(exynos5250_pll_pmux_clks, ARRAY_SIZE(exynos5250_pll_pmux_clks)); + + fin_pll_rate = _get_rate(fin_pll); + + if (fin_pll_rate == (24 * MHZ)) + exynos5250_plls[epll].rate_table = epll_24mhz_tbl; + + vpllsrc = __clk_lookup(mout_vpllsrc); + if (vpllsrc) + mout_vpllsrc_rate = clk_get_rate(vpllsrc); + + if (mout_vpllsrc_rate == (24 * MHZ)) + exynos5250_plls[vpll].rate_table = vpll_24mhz_tbl; + samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls), reg_base); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 3e6501c..378bf98 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -40,6 +40,8 @@ struct samsung_clock_alias { .alias = a,\ } +#define MHZ (1000*1000) + /** * struct samsung_fixed_rate_clock: information about fixed-rate clock * @id: platform specific id of the clock. -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 2/7] clk: samsung: Define a common samsung_clk_register_pll()
On Wed, Jun 19, 2013 at 10:24 PM, Tomasz Figa tomasz.f...@gmail.com wrote: Hi Yadwinder, Generally looks really good, but some comments inline. On Monday 10 of June 2013 18:54:14 Yadwinder Singh Brar wrote: This patch defines a common samsung_clk_register_pll() and its migrating the PLL35xx PLL36xx to use it. Other samsung PLL can also be migrated to it. It also adds exynos5250 exynos5420 PLLs to unique id list of clocks. Since pll2550 pll35xx and pll2650 pll36xx have exactly same clk ops implementation, added pll2550 and pll2650 also. +void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, + unsigned int nr_pll, void __iomem *base) +{ + struct samsung_clk_pll *pll; + struct clk *clk; + struct clk_init_data init; + struct samsung_pll_clock *list = clk_list; + int cnt; + + for (cnt = 0; cnt nr_pll; cnt++, list++) { I'd suggest moving contents of this loop to a function like following? static int __init _samsung_clk_register_pll(struct samsung_pll_clock *pll, void __iomem *base) This will make the code less indented and so more readable. Yes, will do it. + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err(%s: could not allocate pll clk %s\n, + __func__, list-name); + continue; + } + + init.name = list-name; + init.flags = list-flags; + init.parent_names = list-parent_name; + init.num_parents = 1; + + switch (list-type) { + /* clk_ops for 35xx and 2550 are similar */ + case pll_35xx: + case pll_2550: + init.ops = samsung_pll35xx_clk_ops; + break; + /* clk_ops for 36xx and 2650 are similar */ + case pll_36xx: + case pll_2650: + init.ops = samsung_pll36xx_clk_ops; + break; + default: + pr_warn(%s: Unknown pll type for pll clk %s\n, + __func__, list-name); + } + + pll-hw.init = init; + pll-type = list-type; + pll-lock_reg = base + list-lock_offset; + pll-con_reg = base + list-con_offset; + + clk = clk_register(NULL, pll-hw); + if (IS_ERR(clk)) { + pr_err(%s: failed to register pll clock %s\n, + __func__, list-name); + kfree(pll); + continue; + } + + samsung_clk_add_lookup(clk, list-id); + + if (list-alias) + if (clk_register_clkdev(clk, list-alias, + list-dev_name)) What about if (!list-alias) return; ret = clk_register_clkdev(clk, list-alias, list- dev_name); if (ret) pr_err(%s: failed to register lookup for %s, __func__, list-name); its ok, but to me it looks more clear and precise inside if(){ }, as its length and indentation is not much deep. If you really insist we can do it ? + pr_err(%s: failed to register lookup for %s, + __func__, list-name); + } +} +struct samsung_pll_clock { + unsigned intid; + const char *dev_name; + const char *name; + const char *parent_name; + unsigned long flags; + const int con_offset; + const int lock_offset; I don't see any point of having all those const qualifiers of non- pointers. This makes the struct useless for creating and initializing at runtime. OK, will remove it. + enumsamsung_pll_type type; IMHO the enum keyword shouldn't be separated from enum name like this. Any specific reason? Just to keep indentation same for all members, I used tabs :). Otherwise the patch looks fine. Maybe it's a bit too big - things could be done a bit more gradually, like: 1) first add required structs and functions, 2) then move existing clock drivers to use the new API, possibly one patch per driver, 3) remove the old API. This would make the whole change easier to review and, in case of any regressions, easier to track down the problem. OK, I will split it. Thanks, Yadwinder -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 2/7] clk: samsung: Define a common samsung_clk_register_pll().
This patch defines a common samsung_clk_register_pll() and its migrating the PLL35xx PLL36xx to use it. Other samsung PLL can also be migrated to it. This patch also adds exynos5250 PLLs in unique id list of exynos5250 clocks. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c| 40 +++ drivers/clk/samsung/clk-exynos5250.c | 60 +++- drivers/clk/samsung/clk-pll.c| 128 +++-- drivers/clk/samsung/clk-pll.h|9 ++- drivers/clk/samsung/clk.h| 48 + 5 files changed, 178 insertions(+), 107 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index addc738..ba25a1b 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -17,7 +17,6 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h /* Exynos4 clock controller register offsets */ #define SRC_LEFTBUS0x4200 @@ -97,12 +96,14 @@ #define GATE_IP_PERIL 0xc950 #define E4210_GATE_IP_PERIR0xc960 #define GATE_BLOCK 0xc970 +#define E4X12_MPLL_LOCK0x10008 #define E4X12_MPLL_CON00x10108 #define SRC_DMC0x10200 #define SRC_MASK_DMC 0x10300 #define DIV_DMC0 0x10500 #define DIV_DMC1 0x10504 #define GATE_IP_DMC0x10900 +#define APLL_LOCK 0x14000 #define APLL_CON0 0x14100 #define E4210_MPLL_CON00x14108 #define SRC_CPU0x14200 @@ -121,6 +122,12 @@ enum exynos4_soc { EXYNOS4X12, }; +/* list of PLLs to be registered */ +enum exynos4_plls { + apll, mpll, epll, vpll, + nr_plls /* number of PLLs */ +}; + /* * Let each supported clock get a unique id. This id is used to lookup the clock * for device tree based platforms. The clocks are categorized into three @@ -988,6 +995,17 @@ static __initdata struct of_device_id ext_clk_match[] = { {}, }; +struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { + [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, + APLL_CON0, fout_apll), + [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, + E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll), + [epll] = PLL_A(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, + EPLL_CON0, fout_epll), + [vpll] = PLL_A(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, + VPLL_CON0, fout_vpll), +}; + /* register exynos4 clocks */ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom) { @@ -1024,22 +1042,16 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so reg_base + EPLL_CON0, pll_4600); vpll = samsung_clk_register_pll46xx(fout_vpll, mout_vpllsrc, reg_base + VPLL_CON0, pll_4650c); + + samsung_clk_add_lookup(apll, fout_apll); + samsung_clk_add_lookup(mpll, fout_mpll); + samsung_clk_add_lookup(epll, fout_epll); + samsung_clk_add_lookup(vpll, fout_vpll); } else { - apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + APLL_CON0); - mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + E4X12_MPLL_CON0); - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + EPLL_CON0); - vpll = samsung_clk_register_pll36xx(fout_vpll, fin_pll, - reg_base + VPLL_CON0); + samsung_clk_register_pll(exynos4_plls, + ARRAY_SIZE(exynos4_plls), reg_base); } - samsung_clk_add_lookup(apll, fout_apll); - samsung_clk_add_lookup(mpll, fout_mpll); - samsung_clk_add_lookup(epll, fout_epll); - samsung_clk_add_lookup(vpll, fout_vpll); - samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks, ARRAY_SIZE(exynos4_fixed_rate_clks)); samsung_clk_register_mux(exynos4_mux_clks, diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 5c97e75..0418cc1 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -17,11 +17,22 @@ #include linux/of_address.h #include clk.h -#include clk-pll.h +#define APLL_LOCK 0x0 +#define APLL_CON0 0x100 #define SRC_CPU0x200 #define DIV_CPU0 0x500 +#define MPLL_LOCK 0x4000 +#define MPLL_CON0 0x4100 #define
[PATCH v5 3/7] clk: samsung: Add support to register rate_table for PLL3xxx
This patch defines a common rate_table which will contain recommended p, m, s, k values for supported rates that needs to be changed for changing corresponding PLL's rate. Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c|8 drivers/clk/samsung/clk-exynos5250.c | 14 +++--- drivers/clk/samsung/clk-pll.c| 22 -- drivers/clk/samsung/clk-pll.h| 27 +++ drivers/clk/samsung/clk.h| 14 +- 5 files changed, 67 insertions(+), 18 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index ba25a1b..ceee66c 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -997,13 +997,13 @@ static __initdata struct of_device_id ext_clk_match[] = { struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, - APLL_CON0, fout_apll), + APLL_CON0, fout_apll, NULL), [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, - E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll), + E4X12_MPLL_LOCK, E4X12_MPLL_CON0, fout_mpll, NULL), [epll] = PLL_A(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, - EPLL_CON0, fout_epll), + EPLL_CON0, fout_epll, NULL), [vpll] = PLL_A(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, - VPLL_CON0, fout_vpll), + VPLL_CON0, fout_vpll, NULL), }; /* register exynos4 clocks */ diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 0418cc1..a025269 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -491,19 +491,19 @@ static __initdata struct of_device_id ext_clk_match[] = { struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, - APLL_CON0, fout_apll), + APLL_CON0, fout_apll, NULL), [mpll] = PLL_A(pll_35xx, fout_mpll, fout_mpll, fin_pll, MPLL_LOCK, - MPLL_CON0, fout_mpll), + MPLL_CON0, fout_mpll, NULL), [bpll] = PLL(pll_35xx, fout_bpll, fout_bpll, fin_pll, BPLL_LOCK, - BPLL_CON0), + BPLL_CON0, NULL), [gpll] = PLL(pll_35xx, fout_gpll, fout_gpll, fin_pll, GPLL_LOCK, - GPLL_CON0), + GPLL_CON0, NULL), [cpll] = PLL(pll_35xx, fout_cpll, fout_cpll, fin_pll, CPLL_LOCK, - CPLL_CON0), + CPLL_CON0, NULL), [epll] = PLL(pll_36xx, fout_epll, fout_epll, fin_pll, EPLL_LOCK, - EPLL_CON0), + EPLL_CON0, NULL), [vpll] = PLL(pll_36xx, fout_vpll, fout_vpll, fin_pll, VPLL_LOCK, - VPLL_CON0), + VPLL_CON0, NULL), }; /* register exynox5250 clocks */ diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index b83900c..f753c5e 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -18,6 +18,8 @@ struct samsung_clk_pll { void __iomem*lock_reg; void __iomem*con_reg; enum samsung_pll_type type; + unsigned intrate_count; + const struct samsung_pll_rate_table *rate_table; }; #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) @@ -350,7 +352,7 @@ void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, struct clk *clk; struct clk_init_data init; struct samsung_pll_clock *list = clk_list; - int cnt; + int cnt, len; for (cnt = 0; cnt nr_pll; cnt++, list++) { pll = kzalloc(sizeof(*pll), GFP_KERNEL); @@ -365,6 +367,21 @@ void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, init.parent_names = list-parent_name; init.num_parents = 1; + if (list-rate_table) { + /* find count of rates in rate_table */ + for (len = 0; list-rate_table[len].rate != 0; ) + len++; + + pll-rate_count = len; + pll-rate_table = kmemdup(list-rate_table, + list-rate_count * + sizeof(struct samsung_pll_rate_table), + GFP_KERNEL); + WARN(!pll-rate_table, + %s: could not allocate rate table for %s\n, + __func__, list-name); + } + switch (list-type) { case pll_35xx: init.ops = samsung_pll35xx_clk_ops
[PATCH v5 7/7] clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC
Adds the EPLL and VPLL freq table for exynos5250 SoC. Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c | 38 ++ drivers/clk/samsung/clk.h|2 + 2 files changed, 40 insertions(+), 0 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 09da356..d2743f9 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -492,6 +492,29 @@ static __initdata struct of_device_id ext_clk_match[] = { { }, }; +static __initdata struct samsung_pll_rate_table vpll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(26600, 266, 3, 3, 0), + /* Not in UM, but need for eDP on snow */ + PLL_36XX_RATE(7050, 94, 2, 4, 0), + { }, +}; + +static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(19200, 48, 3, 1, 0), + PLL_36XX_RATE(180633600, 45, 3, 1, 10381), + PLL_36XX_RATE(18000, 45, 3, 1, 0), + PLL_36XX_RATE(73728000, 73, 3, 3, 47710), + PLL_36XX_RATE(67737600, 90, 4, 3, 20762), + PLL_36XX_RATE(49152000, 49, 3, 3, 9962), + PLL_36XX_RATE(45158400, 45, 3, 3, 10381), + PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + { }, +}; + struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { [apll] = PLL_A(pll_35xx, fout_apll, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, fout_apll, NULL), @@ -513,6 +536,8 @@ struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = { void __init exynos5250_clk_init(struct device_node *np) { void __iomem *reg_base; + struct clk *vpllsrc; + unsigned long fin_pll_rate, mout_vpllsrc_rate = 0; if (np) { reg_base = of_iomap(np, 0); @@ -530,6 +555,19 @@ void __init exynos5250_clk_init(struct device_node *np) ext_clk_match); samsung_clk_register_mux(exynos5250_pll_pmux_clks, ARRAY_SIZE(exynos5250_pll_pmux_clks)); + + fin_pll_rate = _get_rate(fin_pll); + + if (fin_pll_rate == (24 * MHZ)) + exynos5250_plls[epll].rate_table = epll_24mhz_tbl; + + vpllsrc = __clk_lookup(mout_vpllsrc); + if (vpllsrc) + mout_vpllsrc_rate = clk_get_rate(vpllsrc); + + if (mout_vpllsrc_rate == (24 * MHZ)) + exynos5250_plls[vpll].rate_table = vpll_24mhz_tbl; + samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls), reg_base); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 3e6501c..378bf98 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -40,6 +40,8 @@ struct samsung_clock_alias { .alias = a,\ } +#define MHZ (1000*1000) + /** * struct samsung_fixed_rate_clock: information about fixed-rate clock * @id: platform specific id of the clock. -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 1/7] clk: samsung: Introduce a common samsung_clk_pll struct.
This patch unifies clk strutures used for PLL35xx PLL36xx and adding an extra member lock_reg, so that common code can be factored out. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 30 -- 1 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 89135f6..8224bde 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -13,6 +13,14 @@ #include clk.h #include clk-pll.h +struct samsung_clk_pll { + struct clk_hw hw; + void __iomem*lock_reg; + void __iomem*con_reg; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) + /* * PLL35xx Clock Type */ @@ -24,17 +32,10 @@ #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) -struct samsung_clk_pll35xx { - struct clk_hw hw; - const void __iomem *con_reg; -}; - -#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw) - static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, pll_con; u64 fvco = parent_rate; @@ -56,7 +57,7 @@ static const struct clk_ops samsung_pll35xx_clk_ops = { struct clk * __init samsung_clk_register_pll35xx(const char *name, const char *pname, const void __iomem *con_reg) { - struct samsung_clk_pll35xx *pll; + struct samsung_clk_pll *pll; struct clk *clk; struct clk_init_data init; @@ -100,17 +101,10 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name, #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) -struct samsung_clk_pll36xx { - struct clk_hw hw; - const void __iomem *con_reg; -}; - -#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw) - static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw); + struct samsung_clk_pll *pll = to_clk_pll(hw); u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; u64 fvco = parent_rate; @@ -135,7 +129,7 @@ static const struct clk_ops samsung_pll36xx_clk_ops = { struct clk * __init samsung_clk_register_pll36xx(const char *name, const char *pname, const void __iomem *con_reg) { - struct samsung_clk_pll36xx *pll; + struct samsung_clk_pll *pll; struct clk *clk; struct clk_init_data init; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 5/7] clk: samsung: Add set_rate() clk_ops for PLL36xx
From: Vikas Sajjan vikas.saj...@linaro.org This patch adds set_rate and round_rate clk_ops for PLL36xx Reviewed-by: Tomasz Figa t.f...@samsung.com Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-pll.c | 78 - 1 files changed, 77 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index df419aa..2adf761 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -159,6 +159,8 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = { /* * PLL36xx Clock Type */ +/* Maximum lock time can be 3000 * PDIV cycles */ +#define PLL36XX_LOCK_FACTOR(3000) #define PLL36XX_KDIV_MASK (0x) #define PLL36XX_MDIV_MASK (0x1FF) @@ -167,6 +169,8 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = { #define PLL36XX_MDIV_SHIFT (16) #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) +#define PLL36XX_KDIV_SHIFT (0) +#define PLL36XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -189,8 +193,77 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll36xx_mpk_change( + const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_con0 PLL36XX_MDIV_SHIFT) PLL36XX_MDIV_MASK; + old_pdiv = (pll_con0 PLL36XX_PDIV_SHIFT) PLL36XX_PDIV_MASK; + old_kdiv = (pll_con1 PLL36XX_KDIV_SHIFT) PLL36XX_KDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv || + rate-kdiv != old_kdiv); +} + +static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 tmp, pll_con0, pll_con1; + const struct samsung_pll_rate_table *rate; + + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + pll_con0 = __raw_readl(pll-con_reg); + pll_con1 = __raw_readl(pll-con_reg + 4); + + if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) { + /* If only s change, change just s value only*/ + pll_con0 = ~(PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT); + pll_con0 |= (rate-sdiv PLL36XX_SDIV_SHIFT); + __raw_writel(pll_con0, pll-con_reg); + return 0; + } + + /* Set PLL lock time. */ + __raw_writel(rate-pdiv * PLL36XX_LOCK_FACTOR, pll-lock_reg); + +/* Change PLL PMS values */ + pll_con0 = ~((PLL36XX_MDIV_MASK PLL36XX_MDIV_SHIFT) | + (PLL36XX_PDIV_MASK PLL36XX_PDIV_SHIFT) | + (PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT)); + pll_con0 |= (rate-mdiv PLL36XX_MDIV_SHIFT) | + (rate-pdiv PLL36XX_PDIV_SHIFT) | + (rate-sdiv PLL36XX_SDIV_SHIFT); + __raw_writel(pll_con0, pll-con_reg); + + pll_con1 = ~(PLL36XX_KDIV_MASK PLL36XX_KDIV_SHIFT); + pll_con1 |= rate-kdiv PLL36XX_KDIV_SHIFT; + __raw_writel(pll_con1, pll-con_reg + 4); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = __raw_readl(pll-con_reg); + } while (!(tmp (1 PLL36XX_LOCK_STAT_SHIFT))); + + return 0; +} + static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, + .set_rate = samsung_pll36xx_set_rate, + .round_rate = samsung_pll_round_rate, +}; + +static const struct clk_ops samsung_pll36xx_clk_min_ops = { + .recalc_rate = samsung_pll36xx_recalc_rate, }; /* @@ -489,7 +562,10 @@ void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, init.ops = samsung_pll35xx_clk_ops; break; case pll_36xx: - init.ops = samsung_pll36xx_clk_ops; + if (!pll-rate_table) + init.ops = samsung_pll36xx_clk_min_ops; + else + init.ops = samsung_pll36xx_clk_ops; break; default: pr_warn(%s: Unknown pll type for pll clk %s\n, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 4/7] clk: samsung: Add set_rate() clk_ops for PLL35xx
This patch add set_rate() and round_rate() for PLL35xx Reviewed-by: Doug Anderson diand...@chromium.org Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 104 - 1 files changed, 103 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index f753c5e..df419aa 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -24,16 +24,51 @@ struct samsung_clk_pll { #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) +static const struct samsung_pll_rate_table *samsung_get_pll_settings( + struct samsung_clk_pll *pll, unsigned long rate) +{ + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + for (i = 0; i pll-rate_count; i++) { + if (rate == rate_table[i].rate) + return rate_table[i]; + } + + return NULL; +} + +static long samsung_pll_round_rate(struct clk_hw *hw, + unsigned long drate, unsigned long *prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i pll-rate_count; i++) { + if (drate = rate_table[i].rate) + return rate_table[i].rate; + } + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + /* * PLL35xx Clock Type */ +/* Maximum lock time can be 270 * PDIV cycles */ +#define PLL35XX_LOCK_FACTOR(270) #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) #define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_LOCK_STAT_MASK (0x1) #define PLL35XX_MDIV_SHIFT (16) #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) +#define PLL35XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -53,8 +88,72 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll35xx_mp_change( + const struct samsung_pll_rate_table *rate, u32 pll_con) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_con PLL35XX_MDIV_SHIFT) PLL35XX_MDIV_MASK; + old_pdiv = (pll_con PLL35XX_PDIV_SHIFT) PLL35XX_PDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv); +} + +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 tmp; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + tmp = __raw_readl(pll-con_reg); + + if (!(samsung_pll35xx_mp_change(rate, tmp))) { + /* If only s change, change just s value only*/ + tmp = ~(PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT); + tmp |= rate-sdiv PLL35XX_SDIV_SHIFT; + __raw_writel(tmp, pll-con_reg); + return 0; + } + + /* Set PLL lock time. */ + __raw_writel(rate-pdiv * PLL35XX_LOCK_FACTOR, + pll-lock_reg); + + /* Change PLL PMS values */ + tmp = ~((PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT) | + (PLL35XX_PDIV_MASK PLL35XX_PDIV_SHIFT) | + (PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT)); + tmp |= (rate-mdiv PLL35XX_MDIV_SHIFT) | + (rate-pdiv PLL35XX_PDIV_SHIFT) | + (rate-sdiv PLL35XX_SDIV_SHIFT); + __raw_writel(tmp, pll-con_reg); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = __raw_readl(pll-con_reg); + } while (!(tmp (PLL35XX_LOCK_STAT_MASK +PLL35XX_LOCK_STAT_SHIFT))); + return 0; +} + static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_pll35xx_set_rate, +}; + +static const struct clk_ops samsung_pll35xx_clk_min_ops = { + .recalc_rate = samsung_pll35xx_recalc_rate, }; /* @@ -384,7 +483,10 @@ void __init samsung_clk_register_pll(struct samsung_pll_clock *clk_list, switch (list-type) { case pll_35xx: - init.ops = samsung_pll35xx_clk_ops
[PATCH v5 0/7] Add generic set_rate clk_ops for PLL35xx and PLL36xx for samsung SoCs
This patch series does the following: 1) Unifies the clk strutures and registration function used for PLL35xx PLL36xx, to factor out possible common code. 2) Defines a common rate_table which will contain recommended p, m, s and k values for supported rates that needs to be changed for changing corresponding PLL's rate 3) Adds set_rate() and round_rate() clk_ops for PLL35xx and PLL36xx changes since v4: - Defined common samsung samsung_clk_register_pll() to register a list of PLL and used a struct samsung_pll_clock for passing intialisation data instead of passing as arguments. Now passing LOCK as well as CON0 offset as intialisation data. - Calculated length of rate table while registering PLL instead of getting it as intialisation data. changes since v3: - Used __clk_lookup() instead of adding alias for mout_vpllsrc - Added check for changing only M value in samsung_pll36xx_set_rate() - Modified samsung_pll35xx_mp_change() samsung_pll35xx_set_rate() to improve readabilty. - Made the input rate_table as __init_data which is to be provided while registering PLL and made a copy of that table while registering, so that if multiple tables are their, they can be freed after getting the P, M, S, K setting values from required one. changes since v2: - Added new patch to reorder the MUX registration for mout_vpllsrc MUX before the PLL registrations. And to add the alias for the mout_vpllsrc MUX. - Added a check to confirm parent rate while registrating the PLL rate tables. changes since v1: - removed sorting and bsearch - modified the definition of struct samsung_pll_rate_table - added generic round_rate() - rectified the ops assignment for rate table passed as NULL during PLL registration Is rebased on branch kgene's for-next https://git.kernel.org/cgit/linux/kernel/git/kgene/linux-samsung.git/log/?h=for-next Vikas Sajjan (2): clk: samsung: Add set_rate() clk_ops for PLL36xx clk: samsung: Reorder MUX registration for mout_vpllsrc Yadwinder Singh Brar (5): clk: samsung: Introduce a common samsung_clk_pll struct. clk: samsung: Define a common samsung_clk_register_pll(). clk: samsung: Add support to register rate_table for PLL3xxx clk: samsung: Add set_rate() clk_ops for PLL35xx clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC drivers/clk/samsung/clk-exynos4.c| 40 +++-- drivers/clk/samsung/clk-exynos5250.c | 101 +-- drivers/clk/samsung/clk-pll.c| 330 ++ drivers/clk/samsung/clk-pll.h| 36 - drivers/clk/samsung/clk.h| 54 ++ 5 files changed, 449 insertions(+), 112 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 6/7] clk: samsung: Reorder MUX registration for mout_vpllsrc
From: Vikas Sajjan vikas.saj...@linaro.org While trying to get rate of mout_vpllsrc MUX (parent) for registering the fout_vpll (child), we found get rate was failing. So this patch moves the mout_vpllsrc MUX out of the existing common list and registers the mout_vpllsrc MUX before the PLL registrations. Reviewed-by: Tomasz Figa t.f...@samsung.com Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index a025269..09da356 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -227,6 +227,10 @@ struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = { FFACTOR(none, fout_bplldiv2, fout_bpll, 1, 2, 0), }; +struct samsung_mux_clock exynos5250_pll_pmux_clks[] __initdata = { + MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), +}; + struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, mout_apll, mout_apll_p, SRC_CPU, 0, 1), MUX(none, mout_cpu, mout_cpu_p, SRC_CPU, 16, 1), @@ -234,7 +238,6 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, sclk_mpll, mout_mpll_p, SRC_CORE1, 8, 1), MUX(none, mout_bpll_fout, mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1), MUX(none, sclk_bpll, mout_bpll_p, SRC_CDREX, 0, 1), - MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), MUX(none, sclk_vpll, mout_vpll_p, SRC_TOP2, 16, 1), MUX(none, sclk_epll, mout_epll_p, SRC_TOP2, 12, 1), MUX(none, sclk_cpll, mout_cpll_p, SRC_TOP2, 8, 1), @@ -525,6 +528,8 @@ void __init exynos5250_clk_init(struct device_node *np) samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), ext_clk_match); + samsung_clk_register_mux(exynos5250_pll_pmux_clks, + ARRAY_SIZE(exynos5250_pll_pmux_clks)); samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls), reg_base); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 1/6] clk: samsung: Use clk-base instead of directly using clk-con0 for PLL3xxx
On Thu, Jun 13, 2013 at 3:32 AM, Andrew Bresticker abres...@chromium.org wrote: Doug, Hmm, if done properly, it could simplify PLL registration in SoC clock initialization code a lot. I'm not sure if this is really the best solution (feel free to suggest anything better), but we could put PLLs in an array, like other clocks, e.g. ... exynos4210_pll_clks[] = { CLK_PLL45XX(...), CLK_PLL45XX(...), CLK_PLL46XX(...), CLK_PLL46XX(...), }; and then just call a helper like samsung_clk_register_pll(exynos4210_pll_clks, ARRAY_SIZE(exynos4210_pll_clks)); Something like that looks like what I was thinking. I'd have to see it actually coded up to see if there's something I'm missing that would prevent us from doing that, but I don't see anything. The only issue I see with this is that we may only want to register a rate table with a PLL only if fin_pll is running at a certain rate. On 5250 and 5420, for example, we have EPLL and VPLL rate tables that should only be registered if fin_pll is 24Mhz. We may have to register those separately, but this approach seems fine otherwise. As Andrew Bresticker said, we will face problem with different table, and it will give some pain while handling such cases but I think overall code may look better. Similar thoughts were their in my mind also, but i didn't want to disturb this series :). Anyways, I think we can do it now only rather going for incremental patches after this series. I was thinking to make samsung_clk_register_pll itself little generic instead of using helper, as we are almost duplicating code for most PLLs. A rough picture in my mind was, After implementing generic samung_clk_register_pll(), code may look like below. Its just an idea, please feel free to correct it. Later we can factor out other common clk.ops for PLLs also. this diff is over this series. Assuming a generic samung_clk_register_pll() is their(which i think is not impossible) 8-- --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -493,6 +493,20 @@ static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { PLL_36XX_RATE(32768000, 131, 3, 5, 4719), }; +struct __initdata samsung_pll_init_data samsung_plls[] = { + PLL(pll_3500, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, NULL), + PLL(pll_3500, fout_mpll, fin_pll, MPLL_LOCK, MPLL_CON0, NULL), + PLL(pll_3500, fout_bpll, fin_pll,BPLL_LOCK, BPLL_CON0, NULL), + PLL(pll_3500, fout_gpll, fin_pll,GPLL_LOCK, GPLL_CON0, NULL), + PLL(pll_3500, fout_cpll, fin_pll,BPLL_LOCK, CPLL_CON0, NULL), +}; + +struct __initdata samsung_pll_init_data epll_init_data = + PLL(pll_3600, fout_epll, fin_pll, EPLL_LOCK, EPLL_CON0, NULL); + +struct __initdata samsung_pll_init_data vpll_init_data = + PLL(pll_3600, fout_epll, fin_pll, VPLL_LOCK, VPLL_CON0, NULL); + /* register exynox5250 clocks */ void __init exynos5250_clk_init(struct device_node *np) { @@ -519,44 +533,22 @@ void __init exynos5250_clk_init(struct device_node *np) samsung_clk_register_mux(exynos5250_pll_pmux_clks, ARRAY_SIZE(exynos5250_pll_pmux_clks)); - fin_pll_rate = _get_rate(fin_pll); + samsung_clk_register_pll(samsung_plls, ARRAY_SIZE(samsung_plls)); + vpllsrc = __clk_lookup(mout_vpllsrc); if (vpllsrc) mout_vpllsrc_rate = clk_get_rate(vpllsrc); - apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base, NULL, 0); - mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + 0x4000, NULL, 0); - bpll = samsung_clk_register_pll35xx(fout_bpll, fin_pll, - reg_base + 0x20010, NULL, 0); - gpll = samsung_clk_register_pll35xx(fout_gpll, fin_pll, - reg_base + 0x10050, NULL, 0); - cpll = samsung_clk_register_pll35xx(fout_cpll, fin_pll, - reg_base + 0x10020, NULL, 0); - + fin_pll_rate = _get_rate(fin_pll); if (fin_pll_rate == (24 * MHZ)) { - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10030, epll_24mhz_tbl, - ARRAY_SIZE(epll_24mhz_tbl)); - } else { - pr_warn(%s: valid epll rate_table missing for\n - parent fin_pll:%lu hz\n, __func__, fin_pll_rate); - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10030, NULL, 0); + epll_init_data.rate_table = epll_24mhz_tb; } + samsung_clk_register_pll(fout_epll_data, 1); if (mout_vpllsrc_rate == (24 * MHZ)) { - vpll = samsung_clk_register_pll36xx(fout_vpll,
Re: [PATCH v4 1/6] clk: samsung: Use clk-base instead of directly using clk-con0 for PLL3xxx
On Thu, Jun 13, 2013 at 3:00 PM, Tomasz Figa tomasz.f...@gmail.com wrote: On Thursday 13 of June 2013 12:32:05 Yadwinder Singh Brar wrote: On Thu, Jun 13, 2013 at 3:32 AM, Andrew Bresticker abres...@chromium.org wrote: Doug, Hmm, if done properly, it could simplify PLL registration in SoC clock initialization code a lot. I'm not sure if this is really the best solution (feel free to suggest anything better), but we could put PLLs in an array, like other clocks, e.g. ... exynos4210_pll_clks[] = { CLK_PLL45XX(...), CLK_PLL45XX(...), CLK_PLL46XX(...), CLK_PLL46XX(...), }; and then just call a helper like samsung_clk_register_pll(exynos4210_pll_clks, ARRAY_SIZE(exynos4210_pll_clks)); Something like that looks like what I was thinking. I'd have to see it actually coded up to see if there's something I'm missing that would prevent us from doing that, but I don't see anything. The only issue I see with this is that we may only want to register a rate table with a PLL only if fin_pll is running at a certain rate. On 5250 and 5420, for example, we have EPLL and VPLL rate tables that should only be registered if fin_pll is 24Mhz. We may have to register those separately, but this approach seems fine otherwise. As Andrew Bresticker said, we will face problem with different table, and it will give some pain while handling such cases but I think overall code may look better. Similar thoughts were their in my mind also, but i didn't want to disturb this series :). Yes, I was thinking the same as well, but now that Exynos5420 doesn't follow the 0x100 register spacing, we have a problem :) . Anyways, I think we can do it now only rather going for incremental patches after this series. I was thinking to make samsung_clk_register_pll itself little generic instead of using helper, as we are almost duplicating code for most PLLs. A rough picture in my mind was, After implementing generic samung_clk_register_pll(), code may look like below. Its just an idea, please feel free to correct it. Later we can factor out other common clk.ops for PLLs also. this diff is over this series. Assuming a generic samung_clk_register_pll() is their(which i think is not impossible) 8-- --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -493,6 +493,20 @@ static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { PLL_36XX_RATE(32768000, 131, 3, 5, 4719), }; +struct __initdata samsung_pll_init_data samsung_plls[] = { + PLL(pll_3500, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, NULL), + PLL(pll_3500, fout_mpll, fin_pll, MPLL_LOCK, MPLL_CON0, NULL), + PLL(pll_3500, fout_bpll, fin_pll,BPLL_LOCK, BPLL_CON0, NULL), + PLL(pll_3500, fout_gpll, fin_pll,GPLL_LOCK, GPLL_CON0, NULL), + PLL(pll_3500, fout_cpll, fin_pll,BPLL_LOCK, CPLL_CON0, NULL), +}; + +struct __initdata samsung_pll_init_data epll_init_data = + PLL(pll_3600, fout_epll, fin_pll, EPLL_LOCK, EPLL_CON0, NULL); + +struct __initdata samsung_pll_init_data vpll_init_data = + PLL(pll_3600, fout_epll, fin_pll, VPLL_LOCK, VPLL_CON0, NULL); + This is mostly what I had in my mind. In addition I think I might have a solution for rate tables: If we create another array struct samsung_pll_rate_table *rate_tables_24mhz[] = { apll_rate_table_24mhz, mpll_rate_table_24mhz, /* can be NULL as well, if no support for rate change */ epll_rate_table_24mhz, vpll_rate_table_24mhz, /* ... */ }; which lists rate tables for given input frequency. This relies on making rate tables end with a sentinel, to remove the need of passing array sizes. I think we may also have to make assumption that entries in the arrays rate_tables_24mhz[] and samsung_plls[] should be in same order in both arrays, and which may not be fair assumption, otherwise we have to use some mechanism to identify which rate_table is for which PLL, which will increase code and complexity. Am I missed something or you are thinking something else? Any thoughts from Doug or others ? /* register exynox5250 clocks */ void __init exynos5250_clk_init(struct device_node *np) { @@ -519,44 +533,22 @@ void __init exynos5250_clk_init(struct device_node *np) samsung_clk_register_mux(exynos5250_pll_pmux_clks, ARRAY_SIZE(exynos5250_pll_pmux_clks)); - fin_pll_rate = _get_rate(fin_pll); + samsung_clk_register_pll(samsung_plls, ARRAY_SIZE(samsung_plls)); + ...and then pass it here like: if (fin_pll_rate == 24 * MHZ) { samsung_clk_register_pll(samsung_plls, ARRAY_SIZE(samsung_plls
Re: [PATCH v4 1/6] clk: samsung: Use clk-base instead of directly using clk-con0 for PLL3xxx
On Fri, Jun 14, 2013 at 12:13 AM, Tomasz Figa tomasz.f...@gmail.com wrote: On Friday 14 of June 2013 00:05:31 Yadwinder Singh Brar wrote: On Thu, Jun 13, 2013 at 3:00 PM, Tomasz Figa tomasz.f...@gmail.com wrote: On Thursday 13 of June 2013 12:32:05 Yadwinder Singh Brar wrote: On Thu, Jun 13, 2013 at 3:32 AM, Andrew Bresticker abres...@chromium.org wrote: Doug, Hmm, if done properly, it could simplify PLL registration in SoC clock initialization code a lot. I'm not sure if this is really the best solution (feel free to suggest anything better), but we could put PLLs in an array, like other clocks, e.g. ... exynos4210_pll_clks[] = { CLK_PLL45XX(...), CLK_PLL45XX(...), CLK_PLL46XX(...), CLK_PLL46XX(...), }; and then just call a helper like samsung_clk_register_pll(exynos4210_pll_clks, ARRAY_SIZE(exynos4210_pll_clks)); Something like that looks like what I was thinking. I'd have to see it actually coded up to see if there's something I'm missing that would prevent us from doing that, but I don't see anything. The only issue I see with this is that we may only want to register a rate table with a PLL only if fin_pll is running at a certain rate. On 5250 and 5420, for example, we have EPLL and VPLL rate tables that should only be registered if fin_pll is 24Mhz. We may have to register those separately, but this approach seems fine otherwise. As Andrew Bresticker said, we will face problem with different table, and it will give some pain while handling such cases but I think overall code may look better. Similar thoughts were their in my mind also, but i didn't want to disturb this series :). Yes, I was thinking the same as well, but now that Exynos5420 doesn't follow the 0x100 register spacing, we have a problem :) . Anyways, I think we can do it now only rather going for incremental patches after this series. I was thinking to make samsung_clk_register_pll itself little generic instead of using helper, as we are almost duplicating code for most PLLs. A rough picture in my mind was, After implementing generic samung_clk_register_pll(), code may look like below. Its just an idea, please feel free to correct it. Later we can factor out other common clk.ops for PLLs also. this diff is over this series. Assuming a generic samung_clk_register_pll() is their(which i think is not impossible) 8--- --- --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -493,6 +493,20 @@ static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { PLL_36XX_RATE(32768000, 131, 3, 5, 4719), }; +struct __initdata samsung_pll_init_data samsung_plls[] = { + PLL(pll_3500, fout_apll, fin_pll, APLL_LOCK, APLL_CON0, NULL), + PLL(pll_3500, fout_mpll, fin_pll, MPLL_LOCK, MPLL_CON0, NULL), + PLL(pll_3500, fout_bpll, fin_pll,BPLL_LOCK, BPLL_CON0, NULL), + PLL(pll_3500, fout_gpll, fin_pll,GPLL_LOCK, GPLL_CON0, NULL), + PLL(pll_3500, fout_cpll, fin_pll,BPLL_LOCK, CPLL_CON0, NULL), +}; + +struct __initdata samsung_pll_init_data epll_init_data = + PLL(pll_3600, fout_epll, fin_pll, EPLL_LOCK, EPLL_CON0, NULL); + +struct __initdata samsung_pll_init_data vpll_init_data = + PLL(pll_3600, fout_epll, fin_pll, VPLL_LOCK, VPLL_CON0, NULL); + This is mostly what I had in my mind. In addition I think I might have a solution for rate tables: If we create another array struct samsung_pll_rate_table *rate_tables_24mhz[] = { apll_rate_table_24mhz, mpll_rate_table_24mhz, /* can be NULL as well, if no support for rate change */ epll_rate_table_24mhz, vpll_rate_table_24mhz, /* ... */ }; which lists rate tables for given input frequency. This relies on making rate tables end with a sentinel, to remove the need of passing array sizes. I think we may also have to make assumption that entries in the arrays rate_tables_24mhz[] and samsung_plls[] should be in same order in both arrays, and which may not be fair assumption, otherwise we have to use some mechanism to identify which rate_table is for which PLL, which will increase code and complexity. Am I missed something or you are thinking something else? Yes, this is exactly what I thought. The order and size of rate_tables_24mhz[] would have to be the same as of samsung_plls[], which shouldn't be a problem technically, but adds another responsibility to the person who defines them. OK. but I think this is not a fair assumption. Any thoughts from Doug or others
Re: [PATCH v3 3/6] clk: samsung: Add set_rate() clk_ops for PLL35xx
On Sat, Jun 8, 2013 at 5:42 PM, Tomasz Figa tomasz.f...@gmail.com wrote: On Friday 31 of May 2013 18:01:33 Vikas Sajjan wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com This patch add set_rate() and round_rate() for PLL35xx Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 103 - 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 8226528..9591560 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -27,6 +27,36 @@ struct samsung_clk_pll { #define pll_writel(pll, val, offset) \ __raw_writel(val, (void __iomem *)(pll-base + (offset))); +static const struct samsung_pll_rate_table *samsung_get_pll_settings( + struct samsung_clk_pll *pll, unsigned long rate) +{ + const struct samsung_pll_rate_table *rate_table = pll- rate_table; + int i; + + for (i = 0; i pll-rate_count; i++) { + if (rate == rate_table[i].rate) + return rate_table[i]; + } + + return NULL; +} + +static long samsung_pll_round_rate(struct clk_hw *hw, + unsigned long drate, unsigned long *prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i pll-rate_count; i++) { + if (drate = rate_table[i].rate) + return rate_table[i].rate; + } + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} /* * PLL35xx Clock Type */ @@ -34,12 +64,17 @@ struct samsung_clk_pll { #define PLL35XX_CON0_OFFSET (0x100) #define PLL35XX_CON1_OFFSET (0x104) +/* Maximum lock time can be 270 * PDIV cycles */ +#define PLL35XX_LOCK_FACTOR (270) + #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) #define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_LOCK_STAT_MASK (0x1) #define PLL35XX_MDIV_SHIFT (16) #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) +#define PLL35XX_LOCK_STAT_SHIFT (29) static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -59,8 +94,70 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll35xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con) +{ + if ((mdiv != ((pll_con PLL35XX_MDIV_SHIFT) PLL35XX_MDIV_MASK)) || + (pdiv != ((pll_con PLL35XX_PDIV_SHIFT) PLL35XX_PDIV_MASK))) + return 1; + else + return 0; Readability of this function could be improved by moving some code out of the if clause, like: static inline bool samsung_pll35xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con) { u32 old_mdiv, old_pdiv; old_mdiv = (pll_con PLL35XX_MDIV_SHIFT) PLL35XX_MDIV_MASK; old_pdiv = (pll_con PLL35XX_PDIV_SHIFT) PLL35XX_PDIV_MASK; return (mdiv != old_mdiv || pdiv != old_pdiv); } Yes, it looks neater, I have modified it V4. +} + +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 tmp; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + tmp = pll_readl(pll, PLL35XX_CON0_OFFSET); + + if (!(samsung_pll35xx_mp_change(rate-mdiv, rate-pdiv, tmp))) { + /* If only s change, change just s value only*/ + tmp = ~(PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT); + tmp |= rate-sdiv PLL35XX_SDIV_SHIFT; + pll_writel(pll, tmp, PLL35XX_CON0_OFFSET); To improve readability of this code, return 0 could be added here and following code could be moved out of the else clause. Hmm... I can't see much difference but I have taken this also. Thanks, Yadwinder Best regards, Tomasz + } else { + /* Set PLL lock time. */ + pll_writel(pll, rate-pdiv * PLL35XX_LOCK_FACTOR, + PLL35XX_LOCK_OFFSET); + + /* Change PLL PMS values */ + tmp = ~((PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT) | + (PLL35XX_PDIV_MASK
[PATCH v4 0/6] Add generic set_rate clk_ops for PLL35xx and PLL36xx for samsung SoCs
This patch series does the following: 1) Unifies the clk strutures used for PLL35xx PLL36xx and usues clk-base instead of clk-con0, to factor out possible common code. 2) Defines a common rate_table which will contain recommended p, m, s and k values for supported rates that needs to be changed for changing corresponding PLL's rate 3) Adds set_rate() and round_rate() clk_ops for PLL35xx and PLL36xx changes since v3: - Used __clk_lookup() instead of adding alias for mout_vpllsrc - Added check for changing only M value in samsung_pll36xx_set_rate() - Modified samsung_pll35xx_mp_change() samsung_pll35xx_set_rate() to improve readabilty. - Made the input rate_table as __init_data which is to be provided while registering PLL and made a copy of that table while registering, so that if multiple tables are their, they can be freed after getting the P, M, S, K setting values from required one. changes since v2: - Added new patch to reorder the MUX registration for mout_vpllsrc MUX before the PLL registrations. And to add the alias for the mout_vpllsrc MUX. - Added a check to confirm parent rate while registrating the PLL rate tables. changes since v1: - removed sorting and bsearch - modified the definition of struct samsung_pll_rate_table - added generic round_rate() - rectified the ops assignment for rate table passed as NULL during PLL registration Is rebased on branch kgene's for-next https://git.kernel.org/cgit/linux/kernel/git/kgene/linux-samsung.git/log/?h=for-next Vikas Sajjan (3): clk: samsung: Add set_rate() clk_ops for PLL36xx clk: samsung: Reorder MUX registration for mout_vpllsrc clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC Yadwinder Singh Brar (3): clk: samsung: Use clk-base instead of directly using clk-con0 for PLL3xxx clk: samsung: Add support to register rate_table for PLL3xxx clk: samsung: Add set_rate() clk_ops for PLL35xx drivers/clk/samsung/clk-exynos4.c| 10 +- drivers/clk/samsung/clk-exynos5250.c | 73 +-- drivers/clk/samsung/clk-pll.c| 255 ++ drivers/clk/samsung/clk-pll.h| 35 +- drivers/clk/samsung/clk.h|2 + 5 files changed, 332 insertions(+), 43 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 1/6] clk: samsung: Use clk-base instead of directly using clk-con0 for PLL3xxx
This patch unifies clk strutures used for PLL35xx PLL36xx and uses clk-base instead of directly using clk-con0, so that possible common code can be factored out. It also introdues common pll_[readl/writel] macros for the users of common samsung_clk_pll struct. Reviewed-by: Tomasz Figa t.f...@samsung.com Reviewed-by: Doug Anderson diand...@chromium.org Tested-by: Doug Anderson diand...@chromium.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c| 10 -- drivers/clk/samsung/clk-exynos5250.c | 14 drivers/clk/samsung/clk-pll.c| 54 ++--- drivers/clk/samsung/clk-pll.h|4 +- 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index addc738..ba33bc6 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -97,12 +97,14 @@ #define GATE_IP_PERIL 0xc950 #define E4210_GATE_IP_PERIR0xc960 #define GATE_BLOCK 0xc970 +#define E4X12_MPLL_LOCK0x10008 #define E4X12_MPLL_CON00x10108 #define SRC_DMC0x10200 #define SRC_MASK_DMC 0x10300 #define DIV_DMC0 0x10500 #define DIV_DMC1 0x10504 #define GATE_IP_DMC0x10900 +#define APLL_LOCK 0x14000 #define APLL_CON0 0x14100 #define E4210_MPLL_CON00x14108 #define SRC_CPU0x14200 @@ -1026,13 +1028,13 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so reg_base + VPLL_CON0, pll_4650c); } else { apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + APLL_CON0); + reg_base + APLL_LOCK); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + E4X12_MPLL_CON0); + reg_base + E4X12_MPLL_LOCK); epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + EPLL_CON0); + reg_base + EPLL_LOCK); vpll = samsung_clk_register_pll36xx(fout_vpll, fin_pll, - reg_base + VPLL_CON0); + reg_base + VPLL_LOCK); } samsung_clk_add_lookup(apll, fout_apll); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 5c97e75..687b580 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -491,19 +491,19 @@ void __init exynos5250_clk_init(struct device_node *np) ext_clk_match); apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + 0x100); + reg_base); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + 0x4100); + reg_base + 0x4000); bpll = samsung_clk_register_pll35xx(fout_bpll, fin_pll, - reg_base + 0x20110); + reg_base + 0x20010); gpll = samsung_clk_register_pll35xx(fout_gpll, fin_pll, - reg_base + 0x10150); + reg_base + 0x10050); cpll = samsung_clk_register_pll35xx(fout_cpll, fin_pll, - reg_base + 0x10120); + reg_base + 0x10020); epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10130); + reg_base + 0x10030); vpll = samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc, - reg_base + 0x10140); + reg_base + 0x10040); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, ARRAY_SIZE(exynos5250_fixed_rate_clks)); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 89135f6..a7d8ad9 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -13,9 +13,24 @@ #include clk.h #include clk-pll.h +struct samsung_clk_pll { + struct clk_hw hw; + const void __iomem *base; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) + +#define pll_readl(pll, offset) \ + __raw_readl((void __iomem *)(pll-base + (offset))); +#define pll_writel(pll, val, offset) \ + __raw_writel(val, (void __iomem *)(pll-base + (offset))); + /* * PLL35xx Clock Type */ +#define PLL35XX_LOCK_OFFSET(0x0) +#define PLL35XX_CON0_OFFSET(0x100) +#define PLL35XX_CON1_OFFSET
[PATCH v4 3/6] clk: samsung: Add set_rate() clk_ops for PLL35xx
This patch add set_rate() and round_rate() for PLL35xx Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 104 - 1 files changed, 103 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index cba73a4..319b52b 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -27,6 +27,37 @@ struct samsung_clk_pll { #define pll_writel(pll, val, offset) \ __raw_writel(val, (void __iomem *)(pll-base + (offset))); +static const struct samsung_pll_rate_table *samsung_get_pll_settings( + struct samsung_clk_pll *pll, unsigned long rate) +{ + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + for (i = 0; i pll-rate_count; i++) { + if (rate == rate_table[i].rate) + return rate_table[i]; + } + + return NULL; +} + +static long samsung_pll_round_rate(struct clk_hw *hw, + unsigned long drate, unsigned long *prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate_table = pll-rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i pll-rate_count; i++) { + if (drate = rate_table[i].rate) + return rate_table[i].rate; + } + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + /* * PLL35xx Clock Type */ @@ -34,12 +65,17 @@ struct samsung_clk_pll { #define PLL35XX_CON0_OFFSET(0x100) #define PLL35XX_CON1_OFFSET(0x104) +/* Maximum lock time can be 270 * PDIV cycles */ +#define PLL35XX_LOCK_FACTOR(270) + #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) #define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_LOCK_STAT_MASK (0x1) #define PLL35XX_MDIV_SHIFT (16) #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) +#define PLL35XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -59,8 +95,72 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll35xx_mp_change( + const struct samsung_pll_rate_table *rate, u32 pll_con) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_con PLL35XX_MDIV_SHIFT) PLL35XX_MDIV_MASK; + old_pdiv = (pll_con PLL35XX_PDIV_SHIFT) PLL35XX_PDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv); +} + +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 tmp; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + tmp = pll_readl(pll, PLL35XX_CON0_OFFSET); + + if (!(samsung_pll35xx_mp_change(rate, tmp))) { + /* If only s change, change just s value only*/ + tmp = ~(PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT); + tmp |= rate-sdiv PLL35XX_SDIV_SHIFT; + pll_writel(pll, tmp, PLL35XX_CON0_OFFSET); + } else { + /* Set PLL lock time. */ + pll_writel(pll, rate-pdiv * PLL35XX_LOCK_FACTOR, + PLL35XX_LOCK_OFFSET); + + /* Change PLL PMS values */ + tmp = ~((PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT) | + (PLL35XX_PDIV_MASK PLL35XX_PDIV_SHIFT) | + (PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT)); + tmp |= (rate-mdiv PLL35XX_MDIV_SHIFT) | + (rate-pdiv PLL35XX_PDIV_SHIFT) | + (rate-sdiv PLL35XX_SDIV_SHIFT); + pll_writel(pll, tmp, PLL35XX_CON0_OFFSET); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = pll_readl(pll, PLL35XX_CON0_OFFSET); + } while (!(tmp (PLL35XX_LOCK_STAT_MASK +PLL35XX_LOCK_STAT_SHIFT))); + } + + return 0; +} + static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_pll35xx_set_rate, +}; + +static const
[PATCH v4 2/6] clk: samsung: Add support to register rate_table for PLL3xxx
This patch defines a common rate_table which will contain recommended p, m, s, k values for supported rates that needs to be changed for changing corresponding PLL's rate. Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c|8 +++--- drivers/clk/samsung/clk-exynos5250.c | 14 ++-- drivers/clk/samsung/clk-pll.c| 22 +++- drivers/clk/samsung/clk-pll.h| 35 - 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index ba33bc6..e02a342 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1028,13 +1028,13 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so reg_base + VPLL_CON0, pll_4650c); } else { apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + APLL_LOCK); + reg_base + APLL_LOCK, NULL, 0); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + E4X12_MPLL_LOCK); + reg_base + E4X12_MPLL_LOCK, NULL, 0); epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + EPLL_LOCK); + reg_base + EPLL_LOCK, NULL, 0); vpll = samsung_clk_register_pll36xx(fout_vpll, fin_pll, - reg_base + VPLL_LOCK); + reg_base + VPLL_LOCK, NULL, 0); } samsung_clk_add_lookup(apll, fout_apll); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 687b580..ddf10ca 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -491,19 +491,19 @@ void __init exynos5250_clk_init(struct device_node *np) ext_clk_match); apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base); + reg_base, NULL, 0); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + 0x4000); + reg_base + 0x4000, NULL, 0); bpll = samsung_clk_register_pll35xx(fout_bpll, fin_pll, - reg_base + 0x20010); + reg_base + 0x20010, NULL, 0); gpll = samsung_clk_register_pll35xx(fout_gpll, fin_pll, - reg_base + 0x10050); + reg_base + 0x10050, NULL, 0); cpll = samsung_clk_register_pll35xx(fout_cpll, fin_pll, - reg_base + 0x10020); + reg_base + 0x10020, NULL, 0); epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10030); + reg_base + 0x10030, NULL, 0); vpll = samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc, - reg_base + 0x10040); + reg_base + 0x10040, NULL, 0); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, ARRAY_SIZE(exynos5250_fixed_rate_clks)); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index a7d8ad9..cba73a4 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -16,6 +16,8 @@ struct samsung_clk_pll { struct clk_hw hw; const void __iomem *base; + const struct samsung_pll_rate_table *rate_table; + unsigned int rate_count; }; #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) @@ -62,7 +64,9 @@ static const struct clk_ops samsung_pll35xx_clk_ops = { }; struct clk * __init samsung_clk_register_pll35xx(const char *name, - const char *pname, const void __iomem *base) + const char *pname, const void __iomem *base, + const struct samsung_pll_rate_table *rate_table, + const unsigned int rate_count) { struct samsung_clk_pll *pll; struct clk *clk; @@ -80,6 +84,12 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name, init.parent_names = pname; init.num_parents = 1; + if (rate_table rate_count) { + pll-rate_count = rate_count; + pll-rate_table = kmemdup(rate_table, rate_count * + sizeof(struct samsung_pll_rate_table), GFP_KERNEL); + } + pll-hw.init = init; pll-base = base; @@ -137,7 +147,9 @@ static const struct clk_ops samsung_pll36xx_clk_ops = { }; struct clk * __init samsung_clk_register_pll36xx(const
[PATCH v4 4/6] clk: samsung: Add set_rate() clk_ops for PLL36xx
From: Vikas Sajjan vikas.saj...@linaro.org This patch adds set_rate and round_rate clk_ops for PLL36xx Reviewed-by: Tomasz Figa t.f...@samsung.com Reviewed-by: Doug Anderson diand...@chromium.org Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-pll.c | 79 - 1 files changed, 78 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 319b52b..42b60b5 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -215,6 +215,9 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name, #define PLL36XX_CON0_OFFSET(0x100) #define PLL36XX_CON1_OFFSET(0x104) +/* Maximum lock time can be 3000 * PDIV cycles */ +#define PLL36XX_LOCK_FACTOR(3000) + #define PLL36XX_KDIV_MASK (0x) #define PLL36XX_MDIV_MASK (0x1FF) #define PLL36XX_PDIV_MASK (0x3F) @@ -222,6 +225,8 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name, #define PLL36XX_MDIV_SHIFT (16) #define PLL36XX_PDIV_SHIFT (8) #define PLL36XX_SDIV_SHIFT (0) +#define PLL36XX_KDIV_SHIFT (0) +#define PLL36XX_LOCK_STAT_SHIFT(29) static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -244,8 +249,78 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } +static inline bool samsung_pll36xx_mpk_change( + const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_con0 PLL36XX_MDIV_SHIFT) PLL36XX_MDIV_MASK; + old_pdiv = (pll_con0 PLL36XX_PDIV_SHIFT) PLL36XX_PDIV_MASK; + old_kdiv = (pll_con1 PLL36XX_KDIV_SHIFT) PLL36XX_KDIV_MASK; + + return (rate-mdiv != old_mdiv || rate-pdiv != old_pdiv || + rate-kdiv != old_kdiv); +} + +static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 tmp, pll_con0, pll_con1; + const struct samsung_pll_rate_table *rate; + + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + pll_con0 = pll_readl(pll, PLL36XX_CON0_OFFSET); + pll_con1 = pll_readl(pll, PLL36XX_CON1_OFFSET); + + if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) { + /* If only s change, change just s value only*/ + pll_con0 = ~(PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT); + pll_con0 |= (rate-sdiv PLL36XX_SDIV_SHIFT); + pll_writel(pll, pll_con0, PLL36XX_CON0_OFFSET); + return 0; + } + + /* Set PLL lock time. */ + pll_writel(pll, (rate-pdiv * PLL36XX_LOCK_FACTOR), + PLL36XX_LOCK_OFFSET); + +/* Change PLL PMS values */ + pll_con0 = ~((PLL36XX_MDIV_MASK PLL36XX_MDIV_SHIFT) | + (PLL36XX_PDIV_MASK PLL36XX_PDIV_SHIFT) | + (PLL36XX_SDIV_MASK PLL36XX_SDIV_SHIFT)); + pll_con0 |= (rate-mdiv PLL36XX_MDIV_SHIFT) | + (rate-pdiv PLL36XX_PDIV_SHIFT) | + (rate-sdiv PLL36XX_SDIV_SHIFT); + pll_writel(pll, pll_con0, PLL36XX_CON0_OFFSET); + + pll_con1 = ~(PLL36XX_KDIV_MASK PLL36XX_KDIV_SHIFT); + pll_con1 |= rate-kdiv PLL36XX_KDIV_SHIFT; + pll_writel(pll, pll_con1, PLL36XX_CON1_OFFSET); + + /* wait_lock_time */ + do { + cpu_relax(); + tmp = pll_readl(pll, PLL36XX_CON0_OFFSET); + } while (!(tmp (1 PLL36XX_LOCK_STAT_SHIFT))); + + return 0; +} + static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, + .set_rate = samsung_pll36xx_set_rate, + .round_rate = samsung_pll_round_rate, +}; + +static const struct clk_ops samsung_pll36xx_clk_min_ops = { + .recalc_rate = samsung_pll36xx_recalc_rate, }; struct clk * __init samsung_clk_register_pll36xx(const char *name, @@ -264,7 +339,6 @@ struct clk * __init samsung_clk_register_pll36xx(const char *name, } init.name = name; - init.ops = samsung_pll36xx_clk_ops; init.flags = CLK_GET_RATE_NOCACHE; init.parent_names = pname; init.num_parents = 1; @@ -273,6 +347,9 @@ struct clk * __init samsung_clk_register_pll36xx(const char *name, pll-rate_count = rate_count; pll-rate_table = kmemdup(rate_table, rate_count * sizeof(struct samsung_pll_rate_table), GFP_KERNEL); + init.ops = samsung_pll36xx_clk_ops; + } else { +
[PATCH v4 5/6] clk: samsung: Reorder MUX registration for mout_vpllsrc
From: Vikas Sajjan vikas.saj...@linaro.org While trying to get rate of mout_vpllsrc MUX (parent) for registering the fout_vpll (child), we found get rate was failing. So this patch moves the mout_vpllsrc MUX out of the existing common list and registers the mout_vpllsrc MUX before the PLL registrations. Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos5250.c |8 +++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index ddf10ca..70cc6cf 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -207,6 +207,10 @@ struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = { FFACTOR(none, fout_bplldiv2, fout_bpll, 1, 2, 0), }; +struct samsung_mux_clock exynos5250_pll_pmux_clks[] __initdata = { + MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), +}; + struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, mout_apll, mout_apll_p, SRC_CPU, 0, 1), MUX(none, mout_cpu, mout_cpu_p, SRC_CPU, 16, 1), @@ -214,7 +218,6 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { MUX(none, sclk_mpll, mout_mpll_p, SRC_CORE1, 8, 1), MUX(none, mout_bpll_fout, mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1), MUX(none, sclk_bpll, mout_bpll_p, SRC_CDREX, 0, 1), - MUX(none, mout_vpllsrc, mout_vpllsrc_p, SRC_TOP2, 0, 1), MUX(none, sclk_vpll, mout_vpll_p, SRC_TOP2, 16, 1), MUX(none, sclk_epll, mout_epll_p, SRC_TOP2, 12, 1), MUX(none, sclk_cpll, mout_cpll_p, SRC_TOP2, 8, 1), @@ -490,6 +493,9 @@ void __init exynos5250_clk_init(struct device_node *np) ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), ext_clk_match); + samsung_clk_register_mux(exynos5250_pll_pmux_clks, + ARRAY_SIZE(exynos5250_pll_pmux_clks)); + apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, reg_base, NULL, 0); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 6/6] clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC
Adds the EPLL and VPLL freq table for exynos5250 SoC. Signed-off-by: Vikas Sajjan vikas.saj...@linaro.org --- drivers/clk/samsung/clk-exynos5250.c | 53 -- drivers/clk/samsung/clk.h|2 + 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 70cc6cf..f98c19d 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -472,11 +472,34 @@ static __initdata struct of_device_id ext_clk_match[] = { { }, }; +static __initdata struct samsung_pll_rate_table vpll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(26600, 266, 3, 3, 0), + /* Not in UM, but need for eDP on snow */ + PLL_36XX_RATE(7050, 94, 2, 4, 0), +}; + +static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = { + /* sorted in descending order */ + /* PLL_36XX_RATE(rate, m, p, s, k) */ + PLL_36XX_RATE(19200, 48, 3, 1, 0), + PLL_36XX_RATE(180633600, 45, 3, 1, 10381), + PLL_36XX_RATE(18000, 45, 3, 1, 0), + PLL_36XX_RATE(73728000, 73, 3, 3, 47710), + PLL_36XX_RATE(67737600, 90, 4, 3, 20762), + PLL_36XX_RATE(49152000, 49, 3, 3, 9962), + PLL_36XX_RATE(45158400, 45, 3, 3, 10381), + PLL_36XX_RATE(32768000, 131, 3, 5, 4719), +}; + /* register exynox5250 clocks */ void __init exynos5250_clk_init(struct device_node *np) { void __iomem *reg_base; struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll; + struct clk *vpllsrc; + unsigned long fin_pll_rate, mout_vpllsrc_rate = 0; if (np) { reg_base = of_iomap(np, 0); @@ -496,6 +519,11 @@ void __init exynos5250_clk_init(struct device_node *np) samsung_clk_register_mux(exynos5250_pll_pmux_clks, ARRAY_SIZE(exynos5250_pll_pmux_clks)); + fin_pll_rate = _get_rate(fin_pll); + vpllsrc = __clk_lookup(mout_vpllsrc); + if (vpllsrc) + mout_vpllsrc_rate = clk_get_rate(vpllsrc); + apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, reg_base, NULL, 0); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, @@ -506,10 +534,29 @@ void __init exynos5250_clk_init(struct device_node *np) reg_base + 0x10050, NULL, 0); cpll = samsung_clk_register_pll35xx(fout_cpll, fin_pll, reg_base + 0x10020, NULL, 0); - epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10030, NULL, 0); - vpll = samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc, + + if (fin_pll_rate == (24 * MHZ)) { + epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, + reg_base + 0x10030, epll_24mhz_tbl, + ARRAY_SIZE(epll_24mhz_tbl)); + } else { + pr_warn(%s: valid epll rate_table missing for\n + parent fin_pll:%lu hz\n, __func__, fin_pll_rate); + epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, + reg_base + 0x10030, NULL, 0); + } + + if (mout_vpllsrc_rate == (24 * MHZ)) { + vpll = samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc + , reg_base + 0x10040, vpll_24mhz_tbl, + ARRAY_SIZE(vpll_24mhz_tbl)); + } else { + pr_warn(%s: valid vpll rate_table missing for\n + parent mout_vpllsrc_rate:%lu hz\n, __func__, + mout_vpllsrc_rate); + samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc, reg_base + 0x10040, NULL, 0); + } samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, ARRAY_SIZE(exynos5250_fixed_rate_clks)); diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index e4ad6ea..c997649 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -20,6 +20,8 @@ #include linux/of.h #include linux/of_address.h +#define MHZ (1000*1000) + /** * struct samsung_clock_alias: information about mux clock * @id: platform specific id of the clock. -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/5] clk: samsung: Add support to register rate_table for PLL3xxx
On Wed, Jun 5, 2013 at 7:10 PM, Tomasz Figa t.f...@samsung.com wrote: Hi Yadwinder, On Tuesday 04 of June 2013 17:02:48 Yadwinder Singh Brar wrote: Hi Tomasz, On Mon, Jun 3, 2013 at 8:55 PM, Tomasz Figa t.f...@samsung.com wrote: Hi Yadwinder, On Thursday 30 of May 2013 12:25:40 Yadwinder Singh Brar wrote: Hi Doug, On Thu, May 30, 2013 at 5:14 AM, Doug Anderson diand...@chromium.org wrote: Vikas / Yadwinder, On Wed, May 29, 2013 at 6:37 AM, Vikas Sajjan vikas.saj...@linaro.org wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com This patch defines a common rate_table which will contain recommended p, m, s, k values for supported rates that needs to be changed for changing corresponding PLL's rate. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c|8 drivers/clk/samsung/clk-exynos5250.c | 14 +++--- drivers/clk/samsung/clk-pll.c| 14 -- drivers/clk/samsung/clk-pll.h| 33 +++-- 4 files changed, 54 insertions(+), 15 deletions(-) I also reviewed this in our gerrit https://gerrit.chromium.org/gerrit/#/c/56742/, but I'll summarize here for the list... struct clk * __init samsung_clk_register_pll35xx(const char *name, - const char *pname, const void __iomem *base) + const char *pname, const void __iomem *base, + const struct samsung_pll_rate_table *rate_table, + const unsigned int rate_count) Feels like you should document here that rate_table needs to be sorted and the sort order. sure, we will add comment to sort the table in descending order. +struct samsung_pll_rate_table { + unsigned int rate; nit: extra space before int should be removed. ok Also: you can include rate here if you need a convenient place to store it (which sadly means that this structure can't be const). ...but I do like Tomasz's idea of actually calculating it. You can't know it at compile time since the parent rate comes from the device tree. compatible = samsung,clock-xxti; clock-frequency = 2400; Actually this table should contain the recommended values and if we see the user manual, the input(parent) rate is also a part of recommended table of different output rate for a particular PLL for that SoC. From what I understood in the documentation is that there is a set of recommended P, M, S (, K) tuples for each PLL and they are not dependent on input frequency - f_in and f_out are provided in the table just for reference to see the relation between output frequency and input frequency. If input rate(f_in) gets changed for PLL, then the corresponding output rates(f_out) will change by using same(common) set of recommended P, M, S (, K), and the new set of output rates(f_out) may not be the _required_ set of target rates. So we need different set of P, M, S (,K) values for different f_in. Table should contain set of P, M, S (,K) values for the _required_ target(f_out) rates for a particular input(f_in) rate. I'm not sure what required rates you are talking about. For most PLLs the list of available frequencies seems to be defined by the set of supported PMS values and those are the frequencies that can be set by consumers, not the other way around. There are some cases when some particular frequency must be generated, like PLLs used for audio or video clock sources, but this just means that there must be an entry in PMS table that gives PLL configuration which produces such frequency with used PLL input clock. Yes, I was talking about same cases. Perhaps,I think it holds true in general for PLLs, whose set_rate can be called. I think we should ask some H/W engineer about that to make sure and choose the proper implementation, which will work properly for future cases, instead of ending with something that works just with current cases. We already asked hardware engineer about PMS values for PLL, and we got a table containing recommended P, M ,S values for a given f_in(24 MHz) and required f_out rates. This doesn't answer the question about using those PMS values with different input rate. Kukjin, maybe you can give some information on this or point to a person who could? Please let me know, why you think we are specific to current cases only ? I don't like the idea of having separate tables for each input rate. Just imagine how much data would have to be added if boards with several different input rates showed up. I think by declaring all these different table as __init, and creating a copy to be used while registering, we can save a little memory as well as the unnecessary cost which we have to bear while doing set_rate() and round_rate
Re: [PATCH v2 2/5] clk: samsung: Add support to register rate_table for PLL3xxx
Hi Tomasz, On Mon, Jun 3, 2013 at 8:55 PM, Tomasz Figa t.f...@samsung.com wrote: Hi Yadwinder, On Thursday 30 of May 2013 12:25:40 Yadwinder Singh Brar wrote: Hi Doug, On Thu, May 30, 2013 at 5:14 AM, Doug Anderson diand...@chromium.org wrote: Vikas / Yadwinder, On Wed, May 29, 2013 at 6:37 AM, Vikas Sajjan vikas.saj...@linaro.org wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com This patch defines a common rate_table which will contain recommended p, m, s, k values for supported rates that needs to be changed for changing corresponding PLL's rate. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c|8 drivers/clk/samsung/clk-exynos5250.c | 14 +++--- drivers/clk/samsung/clk-pll.c| 14 -- drivers/clk/samsung/clk-pll.h| 33 +++-- 4 files changed, 54 insertions(+), 15 deletions(-) I also reviewed this in our gerrit https://gerrit.chromium.org/gerrit/#/c/56742/, but I'll summarize here for the list... struct clk * __init samsung_clk_register_pll35xx(const char *name, - const char *pname, const void __iomem *base) + const char *pname, const void __iomem *base, + const struct samsung_pll_rate_table *rate_table, + const unsigned int rate_count) Feels like you should document here that rate_table needs to be sorted and the sort order. sure, we will add comment to sort the table in descending order. +struct samsung_pll_rate_table { + unsigned int rate; nit: extra space before int should be removed. ok Also: you can include rate here if you need a convenient place to store it (which sadly means that this structure can't be const). ...but I do like Tomasz's idea of actually calculating it. You can't know it at compile time since the parent rate comes from the device tree. compatible = samsung,clock-xxti; clock-frequency = 2400; Actually this table should contain the recommended values and if we see the user manual, the input(parent) rate is also a part of recommended table of different output rate for a particular PLL for that SoC. From what I understood in the documentation is that there is a set of recommended P, M, S (, K) tuples for each PLL and they are not dependent on input frequency - f_in and f_out are provided in the table just for reference to see the relation between output frequency and input frequency. If input rate(f_in) gets changed for PLL, then the corresponding output rates(f_out) will change by using same(common) set of recommended P, M, S (, K), and the new set of output rates(f_out) may not be the _required_ set of target rates. So we need different set of P, M, S (,K) values for different f_in. Table should contain set of P, M, S (,K) values for the _required_ target(f_out) rates for a particular input(f_in) rate. I think we should ask some H/W engineer about that to make sure and choose the proper implementation, which will work properly for future cases, instead of ending with something that works just with current cases. We already asked hardware engineer about PMS values for PLL, and we got a table containing recommended P, M ,S values for a given f_in(24 MHz) and required f_out rates. Please let me know, why you think we are specific to current cases only ? Regards, Yadwinder Best regards, -- Tomasz Figa Linux Kernel Developer Samsung RD Institute Poland Samsung Electronics So as Tomasz said input(parent) rate may change with board, then, do those corresponding recommended p, m, s, k will be valid? In case, input(parent) rate changes then we may need different set of p, m ,s, k values recommended for new input rate to get required(recommended to use) output rate. So, we think its better that the p, m, s and k along with the parent is known at the compile time ( or DT ?), as these p, m, s, k values are very much coupled with the parent rate to achieve the required(recommended to use) output rate. Also, since the sorted table is required (sorted based on rate), its better to have the rate in a const rate table. And the whole set of recommended values should come from same place(DT or static table), to keep the things simple and consistent. Moreover, practically for a particular SoC , we use the recommended input(parent) rate only for a PLL. So we should keep the things simple here presently. + unsigned int pdiv; + unsigned int mdiv; + unsigned int sdiv; + unsigned int kdiv; I think kdiv is signed. No, as these values should be the recommended values to be written in corresponding register bits. So it should remain unsigned. K value should be considered as negative only while recalculating rate. As per exynos5250 user manual's section 7.3.2 : K value
Re: [RESEND PATCH 2/5] clk: samsung: Add support to register rate_table for PLL3xxx
Hi Tomasz, On Sat, May 25, 2013 at 3:34 AM, Tomasz Figa tomasz.f...@gmail.com wrote: Hi, Please see my comments inline. On Friday 24 of May 2013 16:01:15 Vikas Sajjan wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com This patch defines a common rate_table which will contain recommended p, m, s and k values for supported rates that needs to be changed for changing corresponding PLL's rate. It also sorts the rate table while registering the PLL rate table. So that this sorted table can be used for making the searching of required rate efficient. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-exynos4.c|8 drivers/clk/samsung/clk-exynos5250.c | 14 +++--- drivers/clk/samsung/clk-pll.c| 35 -- drivers/clk/samsung/clk-pll.h | 27 -- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index cf7d4e7..beff8a1 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1021,13 +1021,13 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so reg_base + VPLL_CON0, pll_4650c); } else { apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base + APLL_LOCK); + reg_base + APLL_LOCK, NULL, 0); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + E4X12_MPLL_LOCK); + reg_base + E4X12_MPLL_LOCK, NULL, 0); epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + EPLL_LOCK); + reg_base + EPLL_LOCK, NULL, 0); vpll = samsung_clk_register_pll36xx(fout_vpll, fin_pll, - reg_base + VPLL_LOCK); + reg_base + VPLL_LOCK, NULL, 0); } samsung_clk_add_lookup(apll, fout_apll); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 687b580..ddf10ca 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -491,19 +491,19 @@ void __init exynos5250_clk_init(struct device_node *np) ext_clk_match); apll = samsung_clk_register_pll35xx(fout_apll, fin_pll, - reg_base); + reg_base, NULL, 0); mpll = samsung_clk_register_pll35xx(fout_mpll, fin_pll, - reg_base + 0x4000); + reg_base + 0x4000, NULL, 0); bpll = samsung_clk_register_pll35xx(fout_bpll, fin_pll, - reg_base + 0x20010); + reg_base + 0x20010, NULL, 0); gpll = samsung_clk_register_pll35xx(fout_gpll, fin_pll, - reg_base + 0x10050); + reg_base + 0x10050, NULL, 0); cpll = samsung_clk_register_pll35xx(fout_cpll, fin_pll, - reg_base + 0x10020); + reg_base + 0x10020, NULL, 0); epll = samsung_clk_register_pll36xx(fout_epll, fin_pll, - reg_base + 0x10030); + reg_base + 0x10030, NULL, 0); vpll = samsung_clk_register_pll36xx(fout_vpll, mout_vpllsrc, - reg_base + 0x10040); + reg_base + 0x10040, NULL, 0); samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, ARRAY_SIZE(exynos5250_fixed_rate_clks)); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 01f17cf..b8c0260 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -10,12 +10,15 @@ */ #include linux/errno.h +#include linux/sort.h #include clk.h #include clk-pll.h struct samsung_clk_pll { struct clk_hw hw; const void __iomem *base; + struct samsung_pll_rate_table *rate_table; + unsigned int rate_count; }; #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) @@ -25,6 +28,14 @@ struct samsung_clk_pll { #define pll_writel(pll, val, offset) \ __raw_writel(val, (void __iomem *)(pll-base + (offset))); +static int samsung_compare_rate(const void *_a, const void *_b) +{ + const struct samsung_pll_rate_table *a = _a; + const struct samsung_pll_rate_table *b = _b; + + return a-rate - b-rate; +} + /* * PLL35xx Clock Type */ @@ -62,7 +73,9 @@ static const struct clk_ops samsung_pll35xx_clk_ops = { }; struct clk * __init samsung_clk_register_pll35xx(const char *name, - const char *pname, const void __iomem *base) + const char *pname
Re: [RESEND PATCH 3/5] clk: samsung: Add set_rate() clk_ops for PLL35xx
On Sat, May 25, 2013 at 3:49 AM, Tomasz Figa tomasz.f...@gmail.com wrote: Hi, On Friday 24 of May 2013 16:01:16 Vikas Sajjan wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com Adds set_rate() and round_rate() clk_ops for PLL35xx The round_rate() implemenation as of now is dummy, it returns the same rate which is passed as input. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/clk/samsung/clk-pll.c | 95 - 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index b8c0260..291cc9e 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -11,6 +11,7 @@ #include linux/errno.h #include linux/sort.h +#include linux/bsearch.h #include clk.h #include clk-pll.h @@ -36,6 +37,21 @@ static int samsung_compare_rate(const void *_a, const void *_b) return a-rate - b-rate; } +static struct samsung_pll_rate_table *samsung_get_pll_settings( + struct samsung_clk_pll *pll, unsigned long rate) +{ + struct samsung_pll_rate_table req_rate, *tmp; + + req_rate.rate = rate; + tmp = bsearch(req_rate, pll-rate_table, pll-rate_count, + sizeof(struct samsung_pll_rate_table), + samsung_compare_rate); Binary search over 10 entries? Isn't it a bit of overkill? Sorry, i couldn't see any over kill? And it may NOT be always 10. + if (tmp) + return tmp; + + return NULL; +} + /* * PLL35xx Clock Type */ @@ -46,9 +62,15 @@ static int samsung_compare_rate(const void *_a, const void *_b) #define PLL35XX_MDIV_MASK (0x3FF) #define PLL35XX_PDIV_MASK (0x3F) #define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_LOCK_STAT_MASK (0x1) #define PLL35XX_MDIV_SHIFT (16) #define PLL35XX_PDIV_SHIFT (8) #define PLL35XX_SDIV_SHIFT (0) +#define PLL35XX_LOCK_STAT_SHIFT (29) + +#define PLL35XX_MDIV(_tmp) ((_tmp) (PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT)) +#define PLL35XX_PDIV(_tmp) ((_tmp) (PLL35XX_PDIV_MASK PLL35XX_PDIV_SHIFT)) +#define PLL35XX_SDIV(_tmp) ((_tmp) (PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT)) static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -68,8 +90,76 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned long)fvco; } -static const struct clk_ops samsung_pll35xx_clk_ops = { +static inline bool samsung_pll35xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con) +{ + if ((mdiv != PLL35XX_MDIV(pll_con)) || (pdiv != PLL35XX_PDIV(pll_con))) + return 1; + else + return 0; +} + +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + struct samsung_pll_rate_table *rate; + + u32 tmp, mdiv, pdiv, sdiv; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err(%s: Invalid rate : %lu for pll clk %s\n, __func__, + drate, __clk_get_name(hw-clk)); + return -EINVAL; + } + + mdiv = PLL35XX_MDIV(rate-pll_con0); + pdiv = PLL35XX_PDIV(rate-pll_con0); + sdiv = PLL35XX_SDIV(rate-pll_con0); You wouldn't need to use those macros if all coefficients were stored as separate fields in the struct. Agree, I will use that. + + tmp = pll_readl(pll, PLL35XX_CON0_OFFSET); + + if (!(samsung_pll35xx_mp_change(mdiv, pdiv, tmp))) { + /* If only s change, change just s value only*/ + tmp = ~(PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT); + tmp |= sdiv; This line is correct, but it looks like it wasn't, because: a) the name suggests that it contains the raw value of S coefficient b) it's real value is hidden between a macro, name of which suggests the same as in a) as well. This makes the code hard to read. We can rename sdiv to sdiv_regval ?? , to improve readability. + pll_writel(pll, tmp, PLL35XX_CON0_OFFSET); + } else { + /* Set PLL lock time. +Maximum lock time can be 270 * PDIV cycles */ + pll_writel(pll, (pdiv PLL35XX_PDIV_SHIFT) * 270, + PLL35XX_LOCK_OFFSET); Hmm, magic constant in the code? Shouldn't it be defined as a macro? Ya, I will define it. + + /* Change PLL PMS values */ + tmp = ~((PLL35XX_MDIV_MASK PLL35XX_MDIV_SHIFT) | + (PLL35XX_PDIV_MASK PLL35XX_PDIV_SHIFT) | + (PLL35XX_SDIV_MASK PLL35XX_SDIV_SHIFT)); + tmp |= mdiv | pdiv | sdiv; This looks strange as well, even if it's correct
[PATCH] regulator: Add ramp_delay to regulator constraints to get used as a configurable parameter.
For some hardwares ramp_delay for BUCKs is a configurable parameter which can be configured through DT or board file.This patch adds ramp_delay to regulator constraints and allow user to configure it for regulators which supports this feature, through DT or board file. It will provide two ways of setting the ramp_delay for a regulator: First, by setting it as constraints in board file(for configurable regulators) and set_machine_constraints() will take care of setting it on hardware by calling(the provided) .set_ramp_delay() operation(callback). Second, by setting it as data in regulator_desc(as fixed/default ramp_delay rate) for a regulator in driver. regulator_set_voltage_time_sel() will give preference to constraints-ramp_delay while reading ramp_delay rate for regulator. Similarly users should also take care accordingly while refering ramp_delay rate(in case of implementing their private .set_voltage_time_sel() callbacks for different regulators). Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- .../devicetree/bindings/regulator/regulator.txt|1 + drivers/regulator/core.c | 23 --- drivers/regulator/of_regulator.c |6 - include/linux/regulator/driver.h |3 ++ include/linux/regulator/machine.h |3 ++ 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 5b7a408..d0a7b12 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -10,6 +10,7 @@ Optional properties: - regulator-always-on: boolean, regulator should never be disabled - regulator-boot-on: bootloader/firmware enabled regulator - name-supply: phandle to the parent supply/regulator node +- regulator-ramp-delay: ramp delay for regulator(in mV/uS) Example: diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 63507a5..0ffd917 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -967,6 +967,14 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev-constraints-ramp_delay ops-set_ramp_delay) { + ret = ops-set_ramp_delay(rdev, rdev-constraints-ramp_delay); + if (ret 0) { + rdev_err(rdev, failed to set ramp_delay\n); + goto out; + } + } + print_constraints(rdev); return 0; out: @@ -2305,10 +2313,17 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, unsigned int new_selector) { - if (rdev-desc-ramp_delay rdev-desc-uV_step) - return DIV_ROUND_UP(rdev-desc-uV_step * - abs(new_selector - old_selector), - rdev-desc-ramp_delay * 1000); + if (rdev-desc-uV_step) { + if (rdev-constraints-ramp_delay) + return DIV_ROUND_UP(rdev-desc-uV_step * + abs(new_selector - old_selector), + rdev-constraints-ramp_delay * 1000); + if (rdev-desc-ramp_delay) + return DIV_ROUND_UP(rdev-desc-uV_step * + abs(new_selector - old_selector), + rdev-desc-ramp_delay * 1000); + rdev_warn(rdev, ramp_delay not set\n); + } return 0; } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 56593b7..e2a7310 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -20,7 +20,7 @@ static void of_get_regulation_constraints(struct device_node *np, struct regulator_init_data **init_data) { const __be32 *min_uV, *max_uV, *uV_offset; - const __be32 *min_uA, *max_uA; + const __be32 *min_uA, *max_uA, *ramp_delay; struct regulation_constraints *constraints = (*init_data)-constraints; constraints-name = of_get_property(np, regulator-name, NULL); @@ -60,6 +60,10 @@ static void of_get_regulation_constraints(struct device_node *np, constraints-always_on = true; else /* status change should be possible if not always on. */ constraints-valid_ops_mask |= REGULATOR_CHANGE_STATUS; + + ramp_delay = of_get_property(np, regulator-ramp-delay, NULL); + if (ramp_delay) + constraints-min_uV = be32_to_cpu(*ramp_delay); } /** diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index ae5c253..ddc155d 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -67,6 +67,8 @@ enum
Re: [PATCH v3 2/2] regulator: Add support for MAX77686.
On Wed, May 23, 2012 at 9:46 AM, Yadwinder Singh Brar yadi.bra...@gmail.com wrote: (adding Kyungmin Park and Samuel Ortiz) Hi, Yes, It happened unintentionally. I didn't know about your patch before submitting the initial version of my patches. I agree with you, I will review your patches and will try to incorporate extra features from your patches. Now I have seen your patches for mfd and regulator drivers. Apparently, it seems that mostly we same features in our patches. Their is no extra feature to be incorporated form your patches. Rather I found device tree support is additional in our patches and mainly their are some differences related to DVS_GPIO and opmode stuff in our patches: 1- Since we are not implementing and using DVS feature through GPIOs, so all(incomplete) stuff related to dvs_gpio is not required currently in our mfd driver presently. 2- Since presently, we are not implementing suspend_enable/disable callbacks in regulator driver, So we don't need opmode related stuff now because I think regulators should come up in normal mode only through .enable callback function. On Wed, May 23, 2012 at 7:10 AM, jonghwa3@samsung.com wrote: Hi, Yadwinder, As you know, both of us, recently, had competition for one driver whether you intend or not. And now, i think it is time to stop this and to find appropriate goal. From now on, i won't update this driver no more. I recommend you to review my patch and apply feature that you can apply. And also check comments that i wrote below. Thanks, Yadwinder. -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 1/2] mfd: Add support for MAX77686.
CC' ing to maintainer. (I forget to add maintainer in cc, sorry for noise). On Tue, May 22, 2012 at 11:26 AM, yadi.bra...@gmail.com wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com MAX77686 is a mulitifunction device with PMIC, RTC and Charger on chip. Th driver provides common support for accessing the device. This is initial version of this driver that supports to enable the chip with its primary I bus.It also includes IRQ and device tree support for MAX77686 chip. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com Reviewed-by: Mark Brown broo...@opensource.wolfsonmicro.com --- Documentation/devicetree/bindings/mfd/max77686.txt | 61 drivers/mfd/Kconfig | 21 ++ drivers/mfd/Makefile | 1 + drivers/mfd/max77686-irq.c | 255 drivers/mfd/max77686.c | 322 include/linux/mfd/max77686-private.h | 282 + include/linux/mfd/max77686.h | 100 ++ 7 files changed, 1042 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/max77686.txt create mode 100644 drivers/mfd/max77686-irq.c create mode 100644 drivers/mfd/max77686.c create mode 100644 include/linux/mfd/max77686-private.h create mode 100644 include/linux/mfd/max77686.h diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt new file mode 100644 index 000..78a47bd --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -0,0 +1,61 @@ +Maxim MAX77686 multi-function device + +MAX77686 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is +interfaced to host controller using i2c interface. PMIC and Charger submodules +are addressed using same i2c slave address where as RTC submodule uses +different slave address,presently for which we are statically creating i2c +client while probing.This document describes the binding for mfd device and +PMIC submodule. + +Required properties: +- compatible : Must be maxim,max77686; +- reg : Specifiec the i2c slave address of PMIC block. +- interrupts : This i2c device has an IRQ line connected to the main SoC. +- interrupt-parent : The parent interrupt controller. + +Optional node: +- max77686,buck_ramp_delay : Ramp delay to be setup for buck2,34. + +- voltage-regulators : The regulators of max77686 have to be instantiated + under subnode named voltage-regulators uing the following format. + + regulator_name { + standard regulator constraints + }; + refer Documentation/devicetree/bindings/regulator/regulator.txt + + The names of regulator should be as follow: + + -LDOn : for LDOs, where n can lie in range 1 to 26. + example: LDO1, LDO2, LDO26. + -BUCKn : for BUCKs, where n can lie in range 1 to 9. + example: BUCK1, BUCK5, BUCK9. + + +Example: + + max77686_pmic@09 { + compatible = maxim,max77686; + interrupt-parent = wakeup_eint; + interrupts = 26 0; + reg = 0x09; + + max77686,buck_ramp_delay = 2; /* default */ + + voltage-regulators { + ldo11_reg: LDO11 { + regulator-name = vdd_ldo11; + regulator-min-microvolt = 190; + regulator-max-microvolt = 190; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = vdd_mif; + regulator-min-microvolt = 95; + regulator-max-microvolt = 130; + regulator-always-on; + regulator-boot-on; + }; + } + diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a4fd173..d8285e5 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -442,6 +442,27 @@ config MFD_MAX8998 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX77686 + bool Maxim Semiconductor MAX77686 PMIC Support + depends on I2C=y GENERIC_HARDIRQS + select MFD_CORE + select REGMAP_I2C + help + Say yes here to support for Maxim Semiconductor MAX77686. + This is a Power Management IC with RTC on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + +config DEBUG_MAX77686 + bool MAX77686 PMIC debugging + depends
Re: [PATCH v3 2/2] regulator: Add support for MAX77686.
(adding Kyungmin Park and Samuel Ortiz) Hi, Yes, It happened unintentionally. I didn't know about your patch before submitting the initial version of my patches. I agree with you, I will review your patches and will try to incorporate extra features from your patches. On Wed, May 23, 2012 at 7:10 AM, jonghwa3@samsung.com wrote: Hi, Yadwinder, As you know, both of us, recently, had competition for one driver whether you intend or not. And now, i think it is time to stop this and to find appropriate goal. From now on, i won't update this driver no more. I recommend you to review my patch and apply feature that you can apply. And also check comments that i wrote below. On 2012년 05월 22일 14:57, yadi.bra...@gmail.com wrote: From: Yadwinder Singh Brar yadi.b...@samsung.com Add support for PMIC/regulator portion of MAX77686 multifunction device. MAX77686 provides LDOs[1-26] and BUCKs[1-9]. This is initial release of driv which supports setting and getting the voltage of a regulator with I2C interface. + return DIV_ROUND_UP(rdev-desc-uV_step * + abs(new_sel - old_sel), + 100); +} + Does LDO also need waiting for voltage change? I afraid it's not. Yes, according to technical reference manual which I have, ramp rate for LDOs is also 100mV/us. + + if (pdata-ramp_delay MAX77686_RAMP_RATE_13MV || + pdata-ramp_delay MAX77686_RAMP_RATE_100MV) + pdata-ramp_delay = MAX77686_RAMP_RATE_27MV; /* default */ If pdata doesn't have proper ramp_delay, it will get value MAX77686_RAMP_RATE_27MV. + + max77686-ramp_delay = pdata-ramp_delay - 1; I think it is better to check pdata-ramp_delay is available. If pdata doesn't have ramp_delay member it might be error. Yes, we have taken care of this case above before setting value of max77686-ramp_delay. + max77686_update_reg(i2c, MAX77686_REG_BUCK2CTRL1, + max77686-ramp_delay 6, RAMP_MASK); + max77686_update_reg(i2c, MAX77686_REG_BUCK3CTRL1, + max77686-ramp_delay 6, RAMP_MASK); + max77686_update_reg(i2c, MAX77686_REG_BUCK4CTRL1, + max77686-ramp_delay 6, RAMP_MASK); + Why do you use i2c client still? If you registered regmap you can use its API. I recommend you to use regmap_update_bits() directly. Yes, we are using regmap_update_bits(). max77686_update_reg() is just a wrapper over it. + platform_set_drvdata(pdev, max77686); + MAX77686 has crystal oscillator in it. And original version of this driver which was written by Chiwoon Byun, registers it as a regulator. As Mark says, we have to change it to use generic clock API. Where do you think should we put them into? In my opinion, it is proper that just leave them in regulator driver because this driver is almost core of PMIC. I already applied generic API in my local repository but i couldn't test yet. Because it crashed with SOC's private clock API. Anyway if you register 32khz clock with generic API ,DEFINE_CLK_GATE() will help you out which defined in linux/clk-private.h. Yes, I was also thinking about where to put it. I am not sure whether this is a proper place to put them. Anyway I will again think about it. Thanks, Yadwinder. -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/2] regulator: Add support for MAX77686.
Hi, On Wed, May 23, 2012 at 7:20 AM, jonghwa3@samsung.com wrote: Hi, again. On 2012년 05월 22일 14:57, yadi.bra...@gmail.com wrote: +static __devinit int max77686_pmic_probe(struct platform_device *pdev) +{ + + for (i = 0; i pdata-num_regulators; i++) { + config.dev = max77686-dev; + config.init_data = pdata-regulators[i].init_data; + config.driver_data = max77686; + config.regmap = iodev-regmap; + + rdev[i] = regulator_register(regulators[i], config); I'm sorry that i missed one. You have to register all regulators unconditionally. Mark brown commented about this to my former patch. 'No, you should unconditionally register all regulators the device physically has. This is useful for debug and simplifies the code.' - from Mark Brown Yes, we are registering all regulators here. As pdata-num_regulators will be equal to ARRAY_SIZE(regulators) Thanks, Yadwinder. -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/2] regulator: Add support for MAX77686.
On Wed, May 23, 2012 at 10:10 AM, jonghwa3@samsung.com wrote: On 2012년 05월 23일 13:16, Yadwinder Singh Brar wrote: + max77686_update_reg(i2c, MAX77686_REG_BUCK2CTRL1, + max77686-ramp_delay 6, RAMP_MASK); + max77686_update_reg(i2c, MAX77686_REG_BUCK3CTRL1, + max77686-ramp_delay 6, RAMP_MASK); + max77686_update_reg(i2c, MAX77686_REG_BUCK4CTRL1, + max77686-ramp_delay 6, RAMP_MASK); + Why do you use i2c client still? If you registered regmap you can use its API. I recommend you to use regmap_update_bits() directly. Yes, we are using regmap_update_bits(). max77686_update_reg() is just a wrapper over it. Yes, i know what you mean. However it doesn't need max77686_update_reg() any more since it uses regmap API. Why don't you just pass iodev-regmap to regmap_update_bits(). It is clear that there is no reason for using i2c client as a medium. Please check regulator and mfd driver of my previous patch. I agree with you we can use directly regmap API. But I preferred max77686_update_reg() because its a common practice to use common read/write API which we define in mfd driver to access that particular mfd device from other drivers. Regards, Yadwinder. -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/2] regulator: Add support for MAX77686.
Hi Mark, On Sun, May 20, 2012 at 3:30 PM, Mark Brown broo...@opensource.wolfsonmicro.com wrote: On Thu, May 17, 2012 at 07:09:27PM +0530, Yadwinder Singh Brar wrote: Looks mostly good. A couple of fairly small things: +static int max77686_get_voltage_sel(struct regulator_dev *rdev) +{ This looks like it should be regulator_get_voltage_sel_regmap(). +static int max77686_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ This looks like it should be regulator_set_voltage_sel_regmap(). Yes, We can use regulator_set_voltage_sel_regmap(), I will replace it. + max77686-ramp_delay = pdata-ramp_delay - 1; + max77686_update_reg(i2c, MAX77686_REG_BUCK2CTRL1, + RAMP_VALUE, RAMP_MASK); + max77686_update_reg(i2c, MAX77686_REG_BUCK3CTRL1, + RAMP_VALUE, RAMP_MASK); + max77686_update_reg(i2c, MAX77686_REG_BUCK4CTRL1, + RAMP_VALUE, RAMP_MASK); This code is unclear because RAMP_VALUE looks like a constant that has nothing to do with ramp_delay when in fact it's actually this: +#define RAMP_VALUE (max77686-ramp_delay 6) which isn't constant - this is why I queried this last time. Just remove the define and write this out directly. The way the code is written at the minute it looks like ramp_delay is just stored and not referred to unless you go searching around the rest of the driver. Ok, I will remove it. Thanks, Yadwinder. -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/2] regulator: Add initial suport for max77686
This patch series adds support for max77686 which is a multifunction device which includes regulator (pmic), rtc and charger sub-blocks within it. The support for mfd driver and regulator driver are added by this patch series. This patch series also includes device tree and irqdomain support for mfd and regulator portions. Implemented the required modification, stated in the recieved review comments. changes since V1: -added regmap support. -implemented .get_voltage_sel, .set_voltage_sel and .set_voltage_time_sel after removing .get_voltage and .set_voltage in regulator driver. -used of_regulator_match() for parsing DT. -added Documentation for Devive Tree binding. This patch series is based on mark_regulator/for-next and has been tested on GAIA board. Yadwinder Singh Brar (2): mfd: Add support for MAX77686. regulator: Add support for MAX77686. Documentation/devicetree/bindings/mfd/max77686.txt | 63 +++ drivers/mfd/Kconfig| 21 + drivers/mfd/Makefile |1 + drivers/mfd/max77686-irq.c | 255 ++ drivers/mfd/max77686.c | 322 drivers/regulator/Kconfig |9 + drivers/regulator/Makefile |1 + drivers/regulator/max77686.c | 512 include/linux/mfd/max77686-private.h | 282 +++ include/linux/mfd/max77686.h | 100 10 files changed, 1566 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/max77686.txt create mode 100644 drivers/mfd/max77686-irq.c create mode 100644 drivers/mfd/max77686.c create mode 100644 drivers/regulator/max77686.c create mode 100644 include/linux/mfd/max77686-private.h create mode 100644 include/linux/mfd/max77686.h -- To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/2] regulator: Add support for MAX77686.
Add support for PMIC/regulator portion of MAX77686 multifunction device. MAX77686 provides LDOs[1-26] and BUCKs[1-9]. This is initial release of driver which supports setting and getting the voltage of a regulator with I2C interface. Signed-off-by: Yadwinder Singh Brar yadi.b...@samsung.com --- drivers/regulator/Kconfig|9 + drivers/regulator/Makefile |1 + drivers/regulator/max77686.c | 512 ++ 3 files changed, 522 insertions(+), 0 deletions(-) create mode 100644 drivers/regulator/max77686.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4ad4e8d..a41d2cf 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -195,6 +195,15 @@ config REGULATOR_MAX8998 via I2C bus. The provided regulator is suitable for S3C6410 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX77686 + tristate Maxim 77686 regulator + depends on MFD_MAX77686 + help + This driver controls a Maxim 77686 voltage regulator via I2C + bus. The provided regulator is suitable for Exynos5 chips to + control VDD_ARM and VDD_INT voltages.It supports LDOs[1-26] + and BUCKs[1-9]. + config REGULATOR_PCAP tristate Motorola PCAP2 regulator driver depends on EZX_PCAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index dcc56dc..949b1f2 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o +obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c new file mode 100644 index 000..7379c29 --- /dev/null +++ b/drivers/regulator/max77686.c @@ -0,0 +1,512 @@ +/* + * max77686.c - Regulator driver for the Maxim 77686 + * + * Copyright (C) 2012 Samsung Electronics Co. Ltd. + * Chiwoong Byun woong.b...@samsung.com + * Yadwinder Singh Brar yadi.b...@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8997.c + */ + +#include linux/module.h +#include linux/bug.h +#include linux/delay.h +#include linux/err.h +#include linux/gpio.h +#include linux/slab.h +#include linux/platform_device.h +#include linux/regulator/driver.h +#include linux/regulator/machine.h +#include linux/regulator/of_regulator.h +#include linux/mfd/max77686.h +#include linux/mfd/max77686-private.h + +#define RAMP_VALUE (max77686-ramp_delay 6) + +struct max77686_data { + struct device *dev; + struct max77686_dev *iodev; + int num_regulators; + struct regulator_dev **rdev; + int ramp_delay; /* index of ramp_delay */ + + /*GPIO-DVS feature is not enabled with the +*current version of MAX77686 driver.*/ +}; + +static int max77686_get_enable_register(struct regulator_dev *rdev, + int *reg, int *mask, int *pattern) +{ + int rid = rdev_get_id(rdev); + + switch (rid) { + case MAX77686_LDO1...MAX77686_LDO26: + *reg = MAX77686_REG_LDO1CTRL1 + (rid - MAX77686_LDO1); + *mask = 0xc0; + *pattern = 0xc0; + break; + case MAX77686_BUCK1: + *reg = MAX77686_REG_BUCK1CTRL; + *mask = 0x03; + *pattern = 0x03; + break; + case MAX77686_BUCK2: + *reg = MAX77686_REG_BUCK2CTRL1; + *mask = 0x30; + *pattern = 0x10; + break; + case MAX77686_BUCK3: + *reg = MAX77686_REG_BUCK3CTRL1; + *mask = 0x30; + *pattern = 0x10; + break; + case MAX77686_BUCK4: + *reg = MAX77686_REG_BUCK4CTRL1; + *mask = 0x30; + *pattern = 0x10; + break; + case MAX77686_BUCK5...MAX77686_BUCK9: + *reg