diff options
| author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-19 07:43:08 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-19 07:43:08 -0500 |
| commit | 178a097d5e6ae57d67310ff18bef0afb5589f2dd (patch) | |
| tree | f64a80af7069b46bea3f55c5f2d90e9881565a36 | |
| parent | 728088871c867f912f8a33ea049b7c4135c95637 (diff) | |
| parent | e81d7bc89c9623ea000890fb4cdf7e731dc21f71 (diff) | |
Merge remote-tracking branch 'regulator/topic/s5m8767' into regulator-next
| -rw-r--r-- | Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | 152 | ||||
| -rw-r--r-- | drivers/mfd/sec-core.c | 75 | ||||
| -rw-r--r-- | drivers/regulator/s5m8767.c | 268 | ||||
| -rw-r--r-- | include/linux/mfd/samsung/core.h | 11 |
4 files changed, 438 insertions, 68 deletions
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt new file mode 100644 index 000000000000..a35ff99003a5 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | * Samsung S5M8767 Voltage and Current Regulator | ||
| 2 | |||
| 3 | The Samsung S5M8767 is a multi-function device which includes volatage and | ||
| 4 | current regulators, rtc, charger controller and other sub-blocks. It is | ||
| 5 | interfaced to the host controller using a i2c interface. Each sub-block is | ||
| 6 | addressed by the host system using different i2c slave address. This document | ||
| 7 | describes the bindings for 'pmic' sub-block of s5m8767. | ||
| 8 | |||
| 9 | Required properties: | ||
| 10 | - compatible: Should be "samsung,s5m8767-pmic". | ||
| 11 | - reg: Specifies the i2c slave address of the pmic block. It should be 0x66. | ||
| 12 | |||
| 13 | - s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV) | ||
| 14 | units for buck2 when changing voltage using gpio dvs. Refer to [1] below | ||
| 15 | for additional information. | ||
| 16 | |||
| 17 | - s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV) | ||
| 18 | units for buck3 when changing voltage using gpio dvs. Refer to [1] below | ||
| 19 | for additional information. | ||
| 20 | |||
| 21 | - s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV) | ||
| 22 | units for buck4 when changing voltage using gpio dvs. Refer to [1] below | ||
| 23 | for additional information. | ||
| 24 | |||
| 25 | - s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used | ||
| 26 | for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines. | ||
| 27 | |||
| 28 | [1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional | ||
| 29 | property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage' | ||
| 30 | property should specify atleast one voltage level (which would be a | ||
| 31 | safe operating voltage). | ||
| 32 | |||
| 33 | If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional | ||
| 34 | property is specified, then all the eight voltage values for the | ||
| 35 | 's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified. | ||
| 36 | |||
| 37 | Optional properties: | ||
| 38 | - interrupt-parent: Specifies the phandle of the interrupt controller to which | ||
| 39 | the interrupts from s5m8767 are delivered to. | ||
| 40 | - interrupts: Interrupt specifiers for two interrupt sources. | ||
| 41 | - First interrupt specifier is for 'irq1' interrupt. | ||
| 42 | - Second interrupt specifier is for 'alert' interrupt. | ||
| 43 | - s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs. | ||
| 44 | - s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs. | ||
| 45 | - s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs. | ||
| 46 | |||
| 47 | Additional properties required if either of the optional properties are used: | ||
| 48 | |||
| 49 | - s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from | ||
| 50 | the possible 8 options selectable by the dvs gpios. The value of this | ||
| 51 | property should be between 0 and 7. If not specified or if out of range, the | ||
| 52 | default value of this property is set to 0. | ||
| 53 | |||
| 54 | - s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used | ||
| 55 | for dvs. The format of the gpio specifier depends in the gpio controller. | ||
| 56 | |||
| 57 | Regulators: The regulators of s5m8767 that have to be instantiated should be | ||
| 58 | included in a sub-node named 'regulators'. Regulator nodes included in this | ||
| 59 | sub-node should be of the format as listed below. | ||
| 60 | |||
| 61 | regulator_name { | ||
| 62 | ldo1_reg: LDO1 { | ||
| 63 | regulator-name = "VDD_ALIVE_1.0V"; | ||
| 64 | regulator-min-microvolt = <1100000>; | ||
| 65 | regulator-max-microvolt = <1100000>; | ||
| 66 | regulator-always-on; | ||
| 67 | regulator-boot-on; | ||
| 68 | op_mode = <1>; /* Normal Mode */ | ||
| 69 | }; | ||
| 70 | }; | ||
| 71 | The above regulator entries are defined in regulator bindings documentation | ||
| 72 | except op_mode description. | ||
| 73 | - op_mode: describes the different operating modes of the LDO's with | ||
| 74 | power mode change in SOC. The different possible values are, | ||
| 75 | 0 - always off mode | ||
| 76 | 1 - on in normal mode | ||
| 77 | 2 - low power mode | ||
| 78 | 3 - suspend mode | ||
| 79 | |||
| 80 | The following are the names of the regulators that the s5m8767 pmic block | ||
| 81 | supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number | ||
| 82 | as per the datasheet of s5m8767. | ||
| 83 | |||
| 84 | - LDOn | ||
| 85 | - valid values for n are 1 to 28 | ||
| 86 | - Example: LDO0, LD01, LDO28 | ||
| 87 | - BUCKn | ||
| 88 | - valid values for n are 1 to 9. | ||
| 89 | - Example: BUCK1, BUCK2, BUCK9 | ||
| 90 | |||
| 91 | The bindings inside the regulator nodes use the standard regulator bindings | ||
| 92 | which are documented elsewhere. | ||
| 93 | |||
| 94 | Example: | ||
| 95 | |||
| 96 | s5m8767_pmic@66 { | ||
| 97 | compatible = "samsung,s5m8767-pmic"; | ||
| 98 | reg = <0x66>; | ||
| 99 | |||
| 100 | s5m8767,pmic-buck2-uses-gpio-dvs; | ||
| 101 | s5m8767,pmic-buck3-uses-gpio-dvs; | ||
| 102 | s5m8767,pmic-buck4-uses-gpio-dvs; | ||
| 103 | |||
| 104 | s5m8767,pmic-buck-default-dvs-idx = <0>; | ||
| 105 | |||
| 106 | s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */ | ||
| 107 | <&gpx0 1 1 0 0>, /* DVS2 */ | ||
| 108 | <&gpx0 2 1 0 0>; /* DVS3 */ | ||
| 109 | |||
| 110 | s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */ | ||
| 111 | <&gpx2 4 1 0 0>, /* SET2 */ | ||
| 112 | <&gpx2 5 1 0 0>; /* SET3 */ | ||
| 113 | |||
| 114 | s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>, | ||
| 115 | <1250000>, <1200000>, | ||
| 116 | <1150000>, <1100000>, | ||
| 117 | <1000000>, <950000>; | ||
| 118 | |||
| 119 | s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>, | ||
| 120 | <1100000>, <1100000>, | ||
| 121 | <1000000>, <1000000>, | ||
| 122 | <1000000>, <1000000>; | ||
| 123 | |||
| 124 | s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>, | ||
| 125 | <1200000>, <1200000>, | ||
| 126 | <1200000>, <1200000>, | ||
| 127 | <1200000>, <1200000>; | ||
| 128 | |||
| 129 | regulators { | ||
| 130 | ldo1_reg: LDO1 { | ||
| 131 | regulator-name = "VDD_ABB_3.3V"; | ||
| 132 | regulator-min-microvolt = <3300000>; | ||
| 133 | regulator-max-microvolt = <3300000>; | ||
| 134 | op_mode = <1>; /* Normal Mode */ | ||
| 135 | }; | ||
| 136 | |||
| 137 | ldo2_reg: LDO2 { | ||
| 138 | regulator-name = "VDD_ALIVE_1.1V"; | ||
| 139 | regulator-min-microvolt = <1100000>; | ||
| 140 | regulator-max-microvolt = <1100000>; | ||
| 141 | regulator-always-on; | ||
| 142 | }; | ||
| 143 | |||
| 144 | buck1_reg: BUCK1 { | ||
| 145 | regulator-name = "VDD_MIF_1.2V"; | ||
| 146 | regulator-min-microvolt = <950000>; | ||
| 147 | regulator-max-microvolt = <1350000>; | ||
| 148 | regulator-always-on; | ||
| 149 | regulator-boot-on; | ||
| 150 | }; | ||
| 151 | }; | ||
| 152 | }; | ||
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 49d361a618d0..77ee26ef5941 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
| 20 | #include <linux/of_irq.h> | ||
| 20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| 21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
| 22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
| @@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = { | |||
| 60 | }, | 61 | }, |
| 61 | }; | 62 | }; |
| 62 | 63 | ||
| 64 | #ifdef CONFIG_OF | ||
| 65 | static struct of_device_id sec_dt_match[] = { | ||
| 66 | { .compatible = "samsung,s5m8767-pmic", | ||
| 67 | .data = (void *)S5M8767X, | ||
| 68 | }, | ||
| 69 | {}, | ||
| 70 | }; | ||
| 71 | #endif | ||
| 72 | |||
| 63 | int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest) | 73 | int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest) |
| 64 | { | 74 | { |
| 65 | return regmap_read(sec_pmic->regmap, reg, dest); | 75 | return regmap_read(sec_pmic->regmap, reg, dest); |
| @@ -95,6 +105,57 @@ static struct regmap_config sec_regmap_config = { | |||
| 95 | .val_bits = 8, | 105 | .val_bits = 8, |
| 96 | }; | 106 | }; |
| 97 | 107 | ||
| 108 | |||
| 109 | #ifdef CONFIG_OF | ||
| 110 | /* | ||
| 111 | * Only the common platform data elements for s5m8767 are parsed here from the | ||
| 112 | * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and | ||
| 113 | * others have to parse their own platform data elements from device tree. | ||
| 114 | * | ||
| 115 | * The s5m8767 platform data structure is instantiated here and the drivers for | ||
| 116 | * the sub-modules need not instantiate another instance while parsing their | ||
| 117 | * platform data. | ||
| 118 | */ | ||
| 119 | static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( | ||
| 120 | struct device *dev) | ||
| 121 | { | ||
| 122 | struct sec_platform_data *pd; | ||
| 123 | |||
| 124 | pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
| 125 | if (!pd) { | ||
| 126 | dev_err(dev, "could not allocate memory for pdata\n"); | ||
| 127 | return ERR_PTR(-ENOMEM); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * ToDo: the 'wakeup' member in the platform data is more of a linux | ||
| 132 | * specfic information. Hence, there is no binding for that yet and | ||
| 133 | * not parsed here. | ||
| 134 | */ | ||
| 135 | |||
| 136 | return pd; | ||
| 137 | } | ||
| 138 | #else | ||
| 139 | static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( | ||
| 140 | struct device *dev) | ||
| 141 | { | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | #endif | ||
| 145 | |||
| 146 | static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, | ||
| 147 | const struct i2c_device_id *id) | ||
| 148 | { | ||
| 149 | #ifdef CONFIG_OF | ||
| 150 | if (i2c->dev.of_node) { | ||
| 151 | const struct of_device_id *match; | ||
| 152 | match = of_match_node(sec_dt_match, i2c->dev.of_node); | ||
| 153 | return (int)match->data; | ||
| 154 | } | ||
| 155 | #endif | ||
| 156 | return (int)id->driver_data; | ||
| 157 | } | ||
| 158 | |||
| 98 | static int sec_pmic_probe(struct i2c_client *i2c, | 159 | static int sec_pmic_probe(struct i2c_client *i2c, |
| 99 | const struct i2c_device_id *id) | 160 | const struct i2c_device_id *id) |
| 100 | { | 161 | { |
| @@ -111,13 +172,22 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
| 111 | sec_pmic->dev = &i2c->dev; | 172 | sec_pmic->dev = &i2c->dev; |
| 112 | sec_pmic->i2c = i2c; | 173 | sec_pmic->i2c = i2c; |
| 113 | sec_pmic->irq = i2c->irq; | 174 | sec_pmic->irq = i2c->irq; |
| 114 | sec_pmic->type = id->driver_data; | 175 | sec_pmic->type = sec_i2c_get_driver_data(i2c, id); |
| 115 | 176 | ||
| 177 | if (sec_pmic->dev->of_node) { | ||
| 178 | pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); | ||
| 179 | if (IS_ERR(pdata)) { | ||
| 180 | ret = PTR_ERR(pdata); | ||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | pdata->device_type = sec_pmic->type; | ||
| 184 | } | ||
| 116 | if (pdata) { | 185 | if (pdata) { |
| 117 | sec_pmic->device_type = pdata->device_type; | 186 | sec_pmic->device_type = pdata->device_type; |
| 118 | sec_pmic->ono = pdata->ono; | 187 | sec_pmic->ono = pdata->ono; |
| 119 | sec_pmic->irq_base = pdata->irq_base; | 188 | sec_pmic->irq_base = pdata->irq_base; |
| 120 | sec_pmic->wakeup = pdata->wakeup; | 189 | sec_pmic->wakeup = pdata->wakeup; |
| 190 | sec_pmic->pdata = pdata; | ||
| 121 | } | 191 | } |
| 122 | 192 | ||
| 123 | sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config); | 193 | sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config); |
| @@ -192,6 +262,7 @@ static struct i2c_driver sec_pmic_driver = { | |||
| 192 | .driver = { | 262 | .driver = { |
| 193 | .name = "sec_pmic", | 263 | .name = "sec_pmic", |
| 194 | .owner = THIS_MODULE, | 264 | .owner = THIS_MODULE, |
| 265 | .of_match_table = of_match_ptr(sec_dt_match), | ||
| 195 | }, | 266 | }, |
| 196 | .probe = sec_pmic_probe, | 267 | .probe = sec_pmic_probe, |
| 197 | .remove = sec_pmic_remove, | 268 | .remove = sec_pmic_remove, |
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 33b65c9ad5d5..8a831947c351 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
| 15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 16 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
| 17 | #include <linux/of_gpio.h> | ||
| 17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| @@ -21,6 +22,9 @@ | |||
| 21 | #include <linux/regulator/machine.h> | 22 | #include <linux/regulator/machine.h> |
| 22 | #include <linux/mfd/samsung/core.h> | 23 | #include <linux/mfd/samsung/core.h> |
| 23 | #include <linux/mfd/samsung/s5m8767.h> | 24 | #include <linux/mfd/samsung/s5m8767.h> |
| 25 | #include <linux/regulator/of_regulator.h> | ||
| 26 | |||
| 27 | #define S5M8767_OPMODE_NORMAL_MODE 0x1 | ||
| 24 | 28 | ||
| 25 | struct s5m8767_info { | 29 | struct s5m8767_info { |
| 26 | struct device *dev; | 30 | struct device *dev; |
| @@ -255,10 +259,8 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev) | |||
| 255 | return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); | 259 | return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); |
| 256 | } | 260 | } |
| 257 | 261 | ||
| 258 | static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) | 262 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) |
| 259 | { | 263 | { |
| 260 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
| 261 | int reg_id = rdev_get_id(rdev); | ||
| 262 | int reg; | 264 | int reg; |
| 263 | 265 | ||
| 264 | switch (reg_id) { | 266 | switch (reg_id) { |
| @@ -296,43 +298,18 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) | |||
| 296 | return -EINVAL; | 298 | return -EINVAL; |
| 297 | } | 299 | } |
| 298 | 300 | ||
| 299 | *_reg = reg; | 301 | return reg; |
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) | ||
| 305 | { | ||
| 306 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | ||
| 307 | int reg, mask, ret; | ||
| 308 | int reg_id = rdev_get_id(rdev); | ||
| 309 | unsigned int val; | ||
| 310 | |||
| 311 | ret = s5m8767_get_voltage_register(rdev, ®); | ||
| 312 | if (ret) | ||
| 313 | return ret; | ||
| 314 | |||
| 315 | mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff; | ||
| 316 | |||
| 317 | ret = sec_reg_read(s5m8767->iodev, reg, &val); | ||
| 318 | if (ret) | ||
| 319 | return ret; | ||
| 320 | |||
| 321 | val &= mask; | ||
| 322 | |||
| 323 | return val; | ||
| 324 | } | 302 | } |
| 325 | 303 | ||
| 326 | static int s5m8767_convert_voltage_to_sel( | 304 | static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc, |
| 327 | const struct sec_voltage_desc *desc, | 305 | int min_vol) |
| 328 | int min_vol, int max_vol) | ||
| 329 | { | 306 | { |
| 330 | int selector = 0; | 307 | int selector = 0; |
| 331 | 308 | ||
| 332 | if (desc == NULL) | 309 | if (desc == NULL) |
| 333 | return -EINVAL; | 310 | return -EINVAL; |
| 334 | 311 | ||
| 335 | if (max_vol < desc->min || min_vol > desc->max) | 312 | if (min_vol > desc->max) |
| 336 | return -EINVAL; | 313 | return -EINVAL; |
| 337 | 314 | ||
| 338 | if (min_vol < desc->min) | 315 | if (min_vol < desc->min) |
| @@ -340,7 +317,7 @@ static int s5m8767_convert_voltage_to_sel( | |||
| 340 | 317 | ||
| 341 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); | 318 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); |
| 342 | 319 | ||
| 343 | if (desc->min + desc->step * selector > max_vol) | 320 | if (desc->min + desc->step * selector > desc->max) |
| 344 | return -EINVAL; | 321 | return -EINVAL; |
| 345 | 322 | ||
| 346 | return selector; | 323 | return selector; |
| @@ -373,15 +350,13 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | |||
| 373 | { | 350 | { |
| 374 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 351 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
| 375 | int reg_id = rdev_get_id(rdev); | 352 | int reg_id = rdev_get_id(rdev); |
| 376 | int reg, mask, ret = 0, old_index, index = 0; | 353 | int old_index, index = 0; |
| 377 | u8 *buck234_vol = NULL; | 354 | u8 *buck234_vol = NULL; |
| 378 | 355 | ||
| 379 | switch (reg_id) { | 356 | switch (reg_id) { |
| 380 | case S5M8767_LDO1 ... S5M8767_LDO28: | 357 | case S5M8767_LDO1 ... S5M8767_LDO28: |
| 381 | mask = 0x3f; | ||
| 382 | break; | 358 | break; |
| 383 | case S5M8767_BUCK1 ... S5M8767_BUCK6: | 359 | case S5M8767_BUCK1 ... S5M8767_BUCK6: |
| 384 | mask = 0xff; | ||
| 385 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) | 360 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) |
| 386 | buck234_vol = &s5m8767->buck2_vol[0]; | 361 | buck234_vol = &s5m8767->buck2_vol[0]; |
| 387 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) | 362 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) |
| @@ -392,7 +367,6 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | |||
| 392 | case S5M8767_BUCK7 ... S5M8767_BUCK8: | 367 | case S5M8767_BUCK7 ... S5M8767_BUCK8: |
| 393 | return -EINVAL; | 368 | return -EINVAL; |
| 394 | case S5M8767_BUCK9: | 369 | case S5M8767_BUCK9: |
| 395 | mask = 0xff; | ||
| 396 | break; | 370 | break; |
| 397 | default: | 371 | default: |
| 398 | return -EINVAL; | 372 | return -EINVAL; |
| @@ -412,11 +386,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | |||
| 412 | else | 386 | else |
| 413 | return s5m8767_set_low(s5m8767); | 387 | return s5m8767_set_low(s5m8767); |
| 414 | } else { | 388 | } else { |
| 415 | ret = s5m8767_get_voltage_register(rdev, ®); | 389 | return regulator_set_voltage_sel_regmap(rdev, selector); |
| 416 | if (ret) | ||
| 417 | return ret; | ||
| 418 | |||
| 419 | return sec_reg_update(s5m8767->iodev, reg, selector, mask); | ||
| 420 | } | 390 | } |
| 421 | } | 391 | } |
| 422 | 392 | ||
| @@ -441,7 +411,7 @@ static struct regulator_ops s5m8767_ops = { | |||
| 441 | .is_enabled = s5m8767_reg_is_enabled, | 411 | .is_enabled = s5m8767_reg_is_enabled, |
| 442 | .enable = s5m8767_reg_enable, | 412 | .enable = s5m8767_reg_enable, |
| 443 | .disable = s5m8767_reg_disable, | 413 | .disable = s5m8767_reg_disable, |
| 444 | .get_voltage_sel = s5m8767_get_voltage_sel, | 414 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 445 | .set_voltage_sel = s5m8767_set_voltage_sel, | 415 | .set_voltage_sel = s5m8767_set_voltage_sel, |
| 446 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, | 416 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, |
| 447 | }; | 417 | }; |
| @@ -508,10 +478,182 @@ static struct regulator_desc regulators[] = { | |||
| 508 | s5m8767_regulator_desc(BUCK9), | 478 | s5m8767_regulator_desc(BUCK9), |
| 509 | }; | 479 | }; |
| 510 | 480 | ||
| 481 | #ifdef CONFIG_OF | ||
| 482 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, | ||
| 483 | struct sec_platform_data *pdata, | ||
| 484 | struct device_node *pmic_np) | ||
| 485 | { | ||
| 486 | int i, gpio; | ||
| 487 | |||
| 488 | for (i = 0; i < 3; i++) { | ||
| 489 | gpio = of_get_named_gpio(pmic_np, | ||
| 490 | "s5m8767,pmic-buck-dvs-gpios", i); | ||
| 491 | if (!gpio_is_valid(gpio)) { | ||
| 492 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | ||
| 493 | return -EINVAL; | ||
| 494 | } | ||
| 495 | pdata->buck_gpios[i] = gpio; | ||
| 496 | } | ||
| 497 | return 0; | ||
| 498 | } | ||
| 499 | |||
| 500 | static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, | ||
| 501 | struct sec_platform_data *pdata, | ||
| 502 | struct device_node *pmic_np) | ||
| 503 | { | ||
| 504 | int i, gpio; | ||
| 505 | |||
| 506 | for (i = 0; i < 3; i++) { | ||
| 507 | gpio = of_get_named_gpio(pmic_np, | ||
| 508 | "s5m8767,pmic-buck-ds-gpios", i); | ||
| 509 | if (!gpio_is_valid(gpio)) { | ||
| 510 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | ||
| 511 | return -EINVAL; | ||
| 512 | } | ||
| 513 | pdata->buck_ds[i] = gpio; | ||
| 514 | } | ||
| 515 | return 0; | ||
| 516 | } | ||
| 517 | |||
| 518 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | ||
| 519 | struct sec_platform_data *pdata) | ||
| 520 | { | ||
| 521 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | ||
| 522 | struct device_node *pmic_np, *regulators_np, *reg_np; | ||
| 523 | struct sec_regulator_data *rdata; | ||
| 524 | struct sec_opmode_data *rmode; | ||
| 525 | unsigned int i, dvs_voltage_nr = 1, ret; | ||
| 526 | |||
| 527 | pmic_np = iodev->dev->of_node; | ||
| 528 | if (!pmic_np) { | ||
| 529 | dev_err(iodev->dev, "could not find pmic sub-node\n"); | ||
| 530 | return -ENODEV; | ||
| 531 | } | ||
| 532 | |||
| 533 | regulators_np = of_find_node_by_name(pmic_np, "regulators"); | ||
| 534 | if (!regulators_np) { | ||
| 535 | dev_err(iodev->dev, "could not find regulators sub-node\n"); | ||
| 536 | return -EINVAL; | ||
| 537 | } | ||
| 538 | |||
| 539 | /* count the number of regulators to be supported in pmic */ | ||
| 540 | pdata->num_regulators = of_get_child_count(regulators_np); | ||
| 541 | |||
| 542 | rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * | ||
| 543 | pdata->num_regulators, GFP_KERNEL); | ||
| 544 | if (!rdata) { | ||
| 545 | dev_err(iodev->dev, | ||
| 546 | "could not allocate memory for regulator data\n"); | ||
| 547 | return -ENOMEM; | ||
| 548 | } | ||
| 549 | |||
| 550 | rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * | ||
| 551 | pdata->num_regulators, GFP_KERNEL); | ||
| 552 | if (!rdata) { | ||
| 553 | dev_err(iodev->dev, | ||
| 554 | "could not allocate memory for regulator mode\n"); | ||
| 555 | return -ENOMEM; | ||
| 556 | } | ||
| 557 | |||
| 558 | pdata->regulators = rdata; | ||
| 559 | pdata->opmode = rmode; | ||
| 560 | for_each_child_of_node(regulators_np, reg_np) { | ||
| 561 | for (i = 0; i < ARRAY_SIZE(regulators); i++) | ||
| 562 | if (!of_node_cmp(reg_np->name, regulators[i].name)) | ||
| 563 | break; | ||
| 564 | |||
| 565 | if (i == ARRAY_SIZE(regulators)) { | ||
| 566 | dev_warn(iodev->dev, | ||
| 567 | "don't know how to configure regulator %s\n", | ||
| 568 | reg_np->name); | ||
| 569 | continue; | ||
| 570 | } | ||
| 571 | |||
| 572 | rdata->id = i; | ||
| 573 | rdata->initdata = of_get_regulator_init_data( | ||
| 574 | &pdev->dev, reg_np); | ||
| 575 | rdata->reg_node = reg_np; | ||
| 576 | rdata++; | ||
| 577 | rmode->id = i; | ||
| 578 | if (of_property_read_u32(reg_np, "op_mode", | ||
| 579 | &rmode->mode)) { | ||
| 580 | dev_warn(iodev->dev, | ||
| 581 | "no op_mode property property at %s\n", | ||
| 582 | reg_np->full_name); | ||
| 583 | |||
| 584 | rmode->mode = S5M8767_OPMODE_NORMAL_MODE; | ||
| 585 | } | ||
| 586 | rmode++; | ||
| 587 | } | ||
| 588 | |||
| 589 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) | ||
| 590 | pdata->buck2_gpiodvs = true; | ||
| 591 | |||
| 592 | if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) | ||
| 593 | pdata->buck3_gpiodvs = true; | ||
| 594 | |||
| 595 | if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) | ||
| 596 | pdata->buck4_gpiodvs = true; | ||
| 597 | |||
| 598 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | ||
| 599 | pdata->buck4_gpiodvs) { | ||
| 600 | ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); | ||
| 601 | if (ret) | ||
| 602 | return -EINVAL; | ||
| 603 | |||
| 604 | if (of_property_read_u32(pmic_np, | ||
| 605 | "s5m8767,pmic-buck-default-dvs-idx", | ||
| 606 | &pdata->buck_default_idx)) { | ||
| 607 | pdata->buck_default_idx = 0; | ||
| 608 | } else { | ||
| 609 | if (pdata->buck_default_idx >= 8) { | ||
| 610 | pdata->buck_default_idx = 0; | ||
| 611 | dev_info(iodev->dev, | ||
| 612 | "invalid value for default dvs index, use 0\n"); | ||
| 613 | } | ||
| 614 | } | ||
| 615 | dvs_voltage_nr = 8; | ||
| 616 | } | ||
| 617 | |||
| 618 | ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); | ||
| 619 | if (ret) | ||
| 620 | return -EINVAL; | ||
| 621 | |||
| 622 | if (of_property_read_u32_array(pmic_np, | ||
| 623 | "s5m8767,pmic-buck2-dvs-voltage", | ||
| 624 | pdata->buck2_voltage, dvs_voltage_nr)) { | ||
| 625 | dev_err(iodev->dev, "buck2 voltages not specified\n"); | ||
| 626 | return -EINVAL; | ||
| 627 | } | ||
| 628 | |||
| 629 | if (of_property_read_u32_array(pmic_np, | ||
| 630 | "s5m8767,pmic-buck3-dvs-voltage", | ||
| 631 | pdata->buck3_voltage, dvs_voltage_nr)) { | ||
| 632 | dev_err(iodev->dev, "buck3 voltages not specified\n"); | ||
| 633 | return -EINVAL; | ||
| 634 | } | ||
| 635 | |||
| 636 | if (of_property_read_u32_array(pmic_np, | ||
| 637 | "s5m8767,pmic-buck4-dvs-voltage", | ||
| 638 | pdata->buck4_voltage, dvs_voltage_nr)) { | ||
| 639 | dev_err(iodev->dev, "buck4 voltages not specified\n"); | ||
| 640 | return -EINVAL; | ||
| 641 | } | ||
| 642 | |||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | #else | ||
| 646 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | ||
| 647 | struct sec_platform_data *pdata) | ||
| 648 | { | ||
| 649 | return 0; | ||
| 650 | } | ||
| 651 | #endif /* CONFIG_OF */ | ||
| 652 | |||
| 511 | static int s5m8767_pmic_probe(struct platform_device *pdev) | 653 | static int s5m8767_pmic_probe(struct platform_device *pdev) |
| 512 | { | 654 | { |
| 513 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 655 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| 514 | struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); | 656 | struct sec_platform_data *pdata = iodev->pdata; |
| 515 | struct regulator_config config = { }; | 657 | struct regulator_config config = { }; |
| 516 | struct regulator_dev **rdev; | 658 | struct regulator_dev **rdev; |
| 517 | struct s5m8767_info *s5m8767; | 659 | struct s5m8767_info *s5m8767; |
| @@ -522,6 +664,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
| 522 | return -ENODEV; | 664 | return -ENODEV; |
| 523 | } | 665 | } |
| 524 | 666 | ||
| 667 | if (iodev->dev->of_node) { | ||
| 668 | ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata); | ||
| 669 | if (ret) | ||
| 670 | return ret; | ||
| 671 | } | ||
| 672 | |||
| 525 | if (pdata->buck2_gpiodvs) { | 673 | if (pdata->buck2_gpiodvs) { |
| 526 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { | 674 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { |
| 527 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 675 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); |
| @@ -577,23 +725,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
| 577 | s5m8767->opmode = pdata->opmode; | 725 | s5m8767->opmode = pdata->opmode; |
| 578 | 726 | ||
| 579 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 727 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
| 580 | pdata->buck2_init, | 728 | pdata->buck2_init); |
| 581 | pdata->buck2_init + | ||
| 582 | buck_voltage_val2.step); | ||
| 583 | 729 | ||
| 584 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); | 730 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); |
| 585 | 731 | ||
| 586 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 732 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
| 587 | pdata->buck3_init, | 733 | pdata->buck3_init); |
| 588 | pdata->buck3_init + | ||
| 589 | buck_voltage_val2.step); | ||
| 590 | 734 | ||
| 591 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); | 735 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); |
| 592 | 736 | ||
| 593 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 737 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
| 594 | pdata->buck4_init, | 738 | pdata->buck4_init); |
| 595 | pdata->buck4_init + | ||
| 596 | buck_voltage_val2.step); | ||
| 597 | 739 | ||
| 598 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); | 740 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); |
| 599 | 741 | ||
| @@ -602,27 +744,21 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
| 602 | s5m8767->buck2_vol[i] = | 744 | s5m8767->buck2_vol[i] = |
| 603 | s5m8767_convert_voltage_to_sel( | 745 | s5m8767_convert_voltage_to_sel( |
| 604 | &buck_voltage_val2, | 746 | &buck_voltage_val2, |
| 605 | pdata->buck2_voltage[i], | 747 | pdata->buck2_voltage[i]); |
| 606 | pdata->buck2_voltage[i] + | ||
| 607 | buck_voltage_val2.step); | ||
| 608 | } | 748 | } |
| 609 | 749 | ||
| 610 | if (s5m8767->buck3_gpiodvs) { | 750 | if (s5m8767->buck3_gpiodvs) { |
| 611 | s5m8767->buck3_vol[i] = | 751 | s5m8767->buck3_vol[i] = |
| 612 | s5m8767_convert_voltage_to_sel( | 752 | s5m8767_convert_voltage_to_sel( |
| 613 | &buck_voltage_val2, | 753 | &buck_voltage_val2, |
| 614 | pdata->buck3_voltage[i], | 754 | pdata->buck3_voltage[i]); |
| 615 | pdata->buck3_voltage[i] + | ||
| 616 | buck_voltage_val2.step); | ||
| 617 | } | 755 | } |
| 618 | 756 | ||
| 619 | if (s5m8767->buck4_gpiodvs) { | 757 | if (s5m8767->buck4_gpiodvs) { |
| 620 | s5m8767->buck4_vol[i] = | 758 | s5m8767->buck4_vol[i] = |
| 621 | s5m8767_convert_voltage_to_sel( | 759 | s5m8767_convert_voltage_to_sel( |
| 622 | &buck_voltage_val2, | 760 | &buck_voltage_val2, |
| 623 | pdata->buck4_voltage[i], | 761 | pdata->buck4_voltage[i]); |
| 624 | pdata->buck4_voltage[i] + | ||
| 625 | buck_voltage_val2.step); | ||
| 626 | } | 762 | } |
| 627 | } | 763 | } |
| 628 | 764 | ||
| @@ -760,11 +896,19 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) | |||
| 760 | (desc->max - desc->min) / desc->step + 1; | 896 | (desc->max - desc->min) / desc->step + 1; |
| 761 | regulators[id].min_uV = desc->min; | 897 | regulators[id].min_uV = desc->min; |
| 762 | regulators[id].uV_step = desc->step; | 898 | regulators[id].uV_step = desc->step; |
| 899 | regulators[id].vsel_reg = | ||
| 900 | s5m8767_get_vsel_reg(id, s5m8767); | ||
| 901 | if (id < S5M8767_BUCK1) | ||
| 902 | regulators[id].vsel_mask = 0x3f; | ||
| 903 | else | ||
| 904 | regulators[id].vsel_mask = 0xff; | ||
| 763 | } | 905 | } |
| 764 | 906 | ||
| 765 | config.dev = s5m8767->dev; | 907 | config.dev = s5m8767->dev; |
| 766 | config.init_data = pdata->regulators[i].initdata; | 908 | config.init_data = pdata->regulators[i].initdata; |
| 767 | config.driver_data = s5m8767; | 909 | config.driver_data = s5m8767; |
| 910 | config.regmap = iodev->regmap; | ||
| 911 | config.of_node = pdata->regulators[i].reg_node; | ||
| 768 | 912 | ||
| 769 | rdev[i] = regulator_register(®ulators[id], &config); | 913 | rdev[i] = regulator_register(®ulators[id], &config); |
| 770 | if (IS_ERR(rdev[i])) { | 914 | if (IS_ERR(rdev[i])) { |
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index b50c38f8bc48..f0f4de3b4ccc 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h | |||
| @@ -26,6 +26,7 @@ enum sec_device_type { | |||
| 26 | /** | 26 | /** |
| 27 | * struct sec_pmic_dev - s5m87xx master device for sub-drivers | 27 | * struct sec_pmic_dev - s5m87xx master device for sub-drivers |
| 28 | * @dev: master device of the chip (can be used to access platform data) | 28 | * @dev: master device of the chip (can be used to access platform data) |
| 29 | * @pdata: pointer to private data used to pass platform data to child | ||
| 29 | * @i2c: i2c client private data for regulator | 30 | * @i2c: i2c client private data for regulator |
| 30 | * @rtc: i2c client private data for rtc | 31 | * @rtc: i2c client private data for rtc |
| 31 | * @iolock: mutex for serializing io access | 32 | * @iolock: mutex for serializing io access |
| @@ -39,6 +40,7 @@ enum sec_device_type { | |||
| 39 | */ | 40 | */ |
| 40 | struct sec_pmic_dev { | 41 | struct sec_pmic_dev { |
| 41 | struct device *dev; | 42 | struct device *dev; |
| 43 | struct sec_platform_data *pdata; | ||
| 42 | struct regmap *regmap; | 44 | struct regmap *regmap; |
| 43 | struct i2c_client *i2c; | 45 | struct i2c_client *i2c; |
| 44 | struct i2c_client *rtc; | 46 | struct i2c_client *rtc; |
| @@ -82,11 +84,11 @@ struct sec_platform_data { | |||
| 82 | 84 | ||
| 83 | int buck_gpios[3]; | 85 | int buck_gpios[3]; |
| 84 | int buck_ds[3]; | 86 | int buck_ds[3]; |
| 85 | int buck2_voltage[8]; | 87 | unsigned int buck2_voltage[8]; |
| 86 | bool buck2_gpiodvs; | 88 | bool buck2_gpiodvs; |
| 87 | int buck3_voltage[8]; | 89 | unsigned int buck3_voltage[8]; |
| 88 | bool buck3_gpiodvs; | 90 | bool buck3_gpiodvs; |
| 89 | int buck4_voltage[8]; | 91 | unsigned int buck4_voltage[8]; |
| 90 | bool buck4_gpiodvs; | 92 | bool buck4_gpiodvs; |
| 91 | 93 | ||
| 92 | int buck_set1; | 94 | int buck_set1; |
| @@ -127,6 +129,7 @@ struct sec_platform_data { | |||
| 127 | struct sec_regulator_data { | 129 | struct sec_regulator_data { |
| 128 | int id; | 130 | int id; |
| 129 | struct regulator_init_data *initdata; | 131 | struct regulator_init_data *initdata; |
| 132 | struct device_node *reg_node; | ||
| 130 | }; | 133 | }; |
| 131 | 134 | ||
| 132 | /* | 135 | /* |
| @@ -136,7 +139,7 @@ struct sec_regulator_data { | |||
| 136 | */ | 139 | */ |
| 137 | struct sec_opmode_data { | 140 | struct sec_opmode_data { |
| 138 | int id; | 141 | int id; |
| 139 | int mode; | 142 | unsigned int mode; |
| 140 | }; | 143 | }; |
| 141 | 144 | ||
| 142 | /* | 145 | /* |
