Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: 88pm860x: Device tree support

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Haojian Zhuang and committed by
Samuel Ortiz
2e57d567 837c8293

+351 -41
+85
Documentation/devicetree/bindings/mfd/88pm860x.txt
··· 1 + * Marvell 88PM860x Power Management IC 2 + 3 + Required parent device properties: 4 + - compatible : "marvell,88pm860x" 5 + - reg : the I2C slave address for the 88pm860x chip 6 + - interrupts : IRQ line for the 88pm860x chip 7 + - interrupt-controller: describes the 88pm860x as an interrupt controller (has its own domain) 8 + - #interrupt-cells : should be 1. 9 + - The cell is the 88pm860x local IRQ number 10 + 11 + Optional parent device properties: 12 + - marvell,88pm860x-irq-read-clr: inicates whether interrupt status is cleared by read 13 + - marvell,88pm860x-slave-addr: 88pm860x are two chips solution. <reg> stores the I2C address 14 + of one chip, and this property stores the I2C address of 15 + another chip. 16 + 17 + 88pm860x consists of a large and varied group of sub-devices: 18 + 19 + Device Supply Names Description 20 + ------ ------------ ----------- 21 + 88pm860x-onkey : : On key 22 + 88pm860x-rtc : : RTC 23 + 88pm8607 : : Regulators 24 + 88pm860x-backlight : : Backlight 25 + 88pm860x-led : : Led 26 + 88pm860x-touch : : Touchscreen 27 + 28 + Example: 29 + 30 + pmic: 88pm860x@34 { 31 + compatible = "marvell,88pm860x"; 32 + reg = <0x34>; 33 + interrupts = <4>; 34 + interrupt-parent = <&intc>; 35 + interrupt-controller; 36 + #interrupt-cells = <1>; 37 + 38 + marvell,88pm860x-irq-read-clr; 39 + marvell,88pm860x-slave-addr = <0x11>; 40 + 41 + regulators { 42 + BUCK1 { 43 + regulator-min-microvolt = <1000000>; 44 + regulator-max-microvolt = <1500000>; 45 + regulator-boot-on; 46 + regulator-always-on; 47 + }; 48 + LDO1 { 49 + regulator-min-microvolt = <1200000>; 50 + regulator-max-microvolt = <2800000>; 51 + regulator-boot-on; 52 + regulator-always-on; 53 + }; 54 + }; 55 + rtc { 56 + marvell,88pm860x-vrtc = <1>; 57 + }; 58 + touch { 59 + marvell,88pm860x-gpadc-prebias = <1>; 60 + marvell,88pm860x-gpadc-slot-cycle = <1>; 61 + marvell,88pm860x-tsi-prebias = <6>; 62 + marvell,88pm860x-pen-prebias = <16>; 63 + marvell,88pm860x-pen-prechg = <2>; 64 + marvell,88pm860x-resistor-X = <300>; 65 + }; 66 + backlights { 67 + backlight-0 { 68 + marvell,88pm860x-iset = <4>; 69 + marvell,88pm860x-pwm = <3>; 70 + }; 71 + backlight-2 { 72 + }; 73 + }; 74 + leds { 75 + led0-red { 76 + marvell,88pm860x-iset = <12>; 77 + }; 78 + led0-green { 79 + marvell,88pm860x-iset = <12>; 80 + }; 81 + led0-blue { 82 + marvell,88pm860x-iset = <12>; 83 + }; 84 + }; 85 + };
+30
Documentation/devicetree/bindings/regulator/88pm860x.txt
··· 1 + Marvell 88PM860x regulator 2 + 3 + Required properties: 4 + - compatible: "marvell,88pm860x" 5 + - reg: I2C slave address 6 + - regulators: A node that houses a sub-node for each regulator within the 7 + device. Each sub-node is identified using the regulator-compatible 8 + property, with valid values listed below. 9 + 10 + Example: 11 + 12 + pmic: 88pm860x@34 { 13 + compatible = "marvell,88pm860x"; 14 + reg = <0x34>; 15 + 16 + regulators { 17 + BUCK1 { 18 + regulator-min-microvolt = <1000000>; 19 + regulator-max-microvolt = <1500000>; 20 + regulator-boot-on; 21 + regulator-always-on; 22 + }; 23 + BUCK3 { 24 + regulator-min-microvolt = <1000000>; 25 + regulator-max-microvolt = <3000000>; 26 + regulator-boot-on; 27 + regulator-always-on; 28 + }; 29 + }; 30 + };
+15
Documentation/devicetree/bindings/video/backlight/88pm860x.txt
··· 1 + 88pm860x-backlight bindings 2 + 3 + Optional properties: 4 + - marvell,88pm860x-iset: Current supplies on backlight device. 5 + - marvell,88pm860x-pwm: PWM frequency on backlight device. 6 + 7 + Example: 8 + 9 + backlights { 10 + backlight-0 { 11 + marvell,88pm860x-iset = <4>; 12 + marvell,88pm860x-pwm = <3>; 13 + }; 14 + backlight-2 { 15 + };
+31 -15
drivers/input/touchscreen/88pm860x-ts.c
··· 10 10 */ 11 11 #include <linux/kernel.h> 12 12 #include <linux/module.h> 13 + #include <linux/of.h> 13 14 #include <linux/platform_device.h> 14 15 #include <linux/i2c.h> 15 16 #include <linux/input.h> ··· 114 113 pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0); 115 114 } 116 115 116 + #ifdef CONFIG_OF 117 + static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, 118 + int *res_x) 119 + { 120 + struct device_node *np = pdev->dev.parent->of_node; 121 + if (!np) 122 + return -ENODEV; 123 + np = of_find_node_by_name(np, "touch"); 124 + if (!np) { 125 + dev_err(&pdev->dev, "Can't find touch node\n"); 126 + return -EINVAL; 127 + } 128 + of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); 129 + return 0; 130 + } 131 + #else 132 + #define pm860x_touch_dt_init(x, y) (-1) 133 + #endif 134 + 117 135 static int __devinit pm860x_touch_probe(struct platform_device *pdev) 118 136 { 119 137 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 120 - struct pm860x_platform_data *pm860x_pdata = \ 121 - pdev->dev.parent->platform_data; 122 - struct pm860x_touch_pdata *pdata = NULL; 138 + struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; 123 139 struct pm860x_touch *touch; 124 - int irq, ret; 140 + int irq, ret, res_x = 0; 125 141 126 142 irq = platform_get_irq(pdev, 0); 127 143 if (irq < 0) { ··· 146 128 return -EINVAL; 147 129 } 148 130 149 - if (!pm860x_pdata) { 150 - dev_err(&pdev->dev, "platform data is missing\n"); 151 - return -EINVAL; 152 - } 153 - 154 - pdata = pm860x_pdata->touch; 155 - if (!pdata) { 156 - dev_err(&pdev->dev, "touchscreen data is missing\n"); 157 - return -EINVAL; 131 + if (pm860x_touch_dt_init(pdev, &res_x)) { 132 + if (pdata) 133 + res_x = pdata->res_x; 134 + else { 135 + dev_err(&pdev->dev, "failed to get platform data\n"); 136 + return -EINVAL; 137 + } 158 138 } 159 139 160 140 touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); ··· 175 159 touch->idev->close = pm860x_touch_close; 176 160 touch->chip = chip; 177 161 touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 178 - touch->irq = irq + chip->irq_base; 179 - touch->res_x = pdata->res_x; 162 + touch->irq = irq; 163 + touch->res_x = res_x; 180 164 input_set_drvdata(touch->idev, touch); 181 165 182 166 ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
+31 -2
drivers/leds/leds-88pm860x.c
··· 12 12 13 13 #include <linux/kernel.h> 14 14 #include <linux/init.h> 15 + #include <linux/of.h> 15 16 #include <linux/platform_device.h> 16 17 #include <linux/i2c.h> 17 18 #include <linux/leds.h> ··· 124 123 schedule_work(&data->work); 125 124 } 126 125 126 + #ifdef CONFIG_OF 127 + static int pm860x_led_dt_init(struct platform_device *pdev, 128 + struct pm860x_led *data) 129 + { 130 + struct device_node *nproot = pdev->dev.parent->of_node, *np; 131 + int iset = 0; 132 + if (!nproot) 133 + return -ENODEV; 134 + nproot = of_find_node_by_name(nproot, "leds"); 135 + if (!nproot) { 136 + dev_err(&pdev->dev, "failed to find leds node\n"); 137 + return -ENODEV; 138 + } 139 + for_each_child_of_node(nproot, np) { 140 + if (!of_node_cmp(np->name, data->name)) { 141 + of_property_read_u32(np, "marvell,88pm860x-iset", 142 + &iset); 143 + data->iset = PM8606_LED_CURRENT(iset); 144 + break; 145 + } 146 + } 147 + return 0; 148 + } 149 + #else 150 + #define pm860x_led_dt_init(x, y) (-1) 151 + #endif 152 + 127 153 static int pm860x_led_probe(struct platform_device *pdev) 128 154 { 129 155 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); ··· 207 179 data->chip = chip; 208 180 data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; 209 181 data->port = pdev->id; 210 - if (pdata && pdata->iset) 211 - data->iset = pdata->iset; 182 + if (pm860x_led_dt_init(pdev, data)) 183 + if (pdata) 184 + data->iset = pdata->iset; 212 185 213 186 data->current_brightness = 0; 214 187 data->cdev.name = data->name;
+53 -9
drivers/mfd/88pm860x-core.c
··· 16 16 #include <linux/irq.h> 17 17 #include <linux/interrupt.h> 18 18 #include <linux/irqdomain.h> 19 + #include <linux/of.h> 20 + #include <linux/of_platform.h> 19 21 #include <linux/platform_device.h> 20 22 #include <linux/regmap.h> 21 23 #include <linux/slab.h> ··· 1114 1112 mfd_remove_devices(chip->dev); 1115 1113 } 1116 1114 1117 - static const struct i2c_device_id pm860x_id_table[] = { 1118 - { "88PM860x", 0 }, 1119 - {} 1120 - }; 1121 - MODULE_DEVICE_TABLE(i2c, pm860x_id_table); 1122 - 1123 1115 static int verify_addr(struct i2c_client *i2c) 1124 1116 { 1125 1117 unsigned short addr_8607[] = {0x30, 0x34}; ··· 1140 1144 .val_bits = 8, 1141 1145 }; 1142 1146 1147 + static int __devinit pm860x_dt_init(struct device_node *np, 1148 + struct device *dev, 1149 + struct pm860x_platform_data *pdata) 1150 + { 1151 + int ret; 1152 + 1153 + if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) 1154 + pdata->irq_mode = 1; 1155 + ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", 1156 + &pdata->companion_addr); 1157 + if (ret) { 1158 + dev_err(dev, "Not found \"marvell,88pm860x-slave-addr\" " 1159 + "property\n"); 1160 + pdata->companion_addr = 0; 1161 + } 1162 + return 0; 1163 + } 1164 + 1143 1165 static int __devinit pm860x_probe(struct i2c_client *client, 1144 1166 const struct i2c_device_id *id) 1145 1167 { 1146 1168 struct pm860x_platform_data *pdata = client->dev.platform_data; 1169 + struct device_node *node = client->dev.of_node; 1147 1170 struct pm860x_chip *chip; 1148 1171 int ret; 1149 1172 1150 - if (!pdata) { 1173 + if (node && !pdata) { 1174 + /* parse DT to get platform data */ 1175 + pdata = devm_kzalloc(&client->dev, 1176 + sizeof(struct pm860x_platform_data), 1177 + GFP_KERNEL); 1178 + if (!pdata) 1179 + return -ENOMEM; 1180 + ret = pm860x_dt_init(node, &client->dev, pdata); 1181 + if (ret) 1182 + goto err; 1183 + } else if (!pdata) { 1151 1184 pr_info("No platform data in %s!\n", __func__); 1152 1185 return -EINVAL; 1153 1186 } 1154 1187 1155 1188 chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); 1156 - if (chip == NULL) 1157 - return -ENOMEM; 1189 + if (chip == NULL) { 1190 + ret = -ENOMEM; 1191 + goto err; 1192 + } 1158 1193 1159 1194 chip->id = verify_addr(client); 1160 1195 chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); ··· 1225 1198 1226 1199 pm860x_device_init(chip, pdata); 1227 1200 return 0; 1201 + err: 1202 + if (node) 1203 + devm_kfree(&client->dev, pdata); 1204 + return ret; 1228 1205 } 1229 1206 1230 1207 static int __devexit pm860x_remove(struct i2c_client *client) ··· 1269 1238 1270 1239 static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); 1271 1240 1241 + static const struct i2c_device_id pm860x_id_table[] = { 1242 + { "88PM860x", 0 }, 1243 + {} 1244 + }; 1245 + MODULE_DEVICE_TABLE(i2c, pm860x_id_table); 1246 + 1247 + static const struct of_device_id pm860x_dt_ids[] = { 1248 + { .compatible = "marvell,88pm860x", }, 1249 + {}, 1250 + }; 1251 + MODULE_DEVICE_TABLE(of, pm860x_dt_ids); 1252 + 1272 1253 static struct i2c_driver pm860x_driver = { 1273 1254 .driver = { 1274 1255 .name = "88PM860x", 1275 1256 .owner = THIS_MODULE, 1276 1257 .pm = &pm860x_pm_ops, 1258 + .of_match_table = of_match_ptr(pm860x_dt_ids), 1277 1259 }, 1278 1260 .probe = pm860x_probe, 1279 1261 .remove = __devexit_p(pm860x_remove),
+34 -1
drivers/regulator/88pm8607.c
··· 12 12 #include <linux/init.h> 13 13 #include <linux/err.h> 14 14 #include <linux/i2c.h> 15 + #include <linux/of.h> 16 + #include <linux/regulator/of_regulator.h> 15 17 #include <linux/platform_device.h> 16 18 #include <linux/regulator/driver.h> 17 19 #include <linux/regulator/machine.h> ··· 366 364 PM8606_PREG(PREREGULATORB, 5), 367 365 }; 368 366 367 + #ifdef CONFIG_OF 368 + static int pm8607_regulator_dt_init(struct platform_device *pdev, 369 + struct pm8607_regulator_info *info, 370 + struct regulator_config *config) 371 + { 372 + struct device_node *nproot, *np; 373 + nproot = pdev->dev.parent->of_node; 374 + if (!nproot) 375 + return -ENODEV; 376 + nproot = of_find_node_by_name(nproot, "regulators"); 377 + if (!nproot) { 378 + dev_err(&pdev->dev, "failed to find regulators node\n"); 379 + return -ENODEV; 380 + } 381 + for_each_child_of_node(nproot, np) { 382 + if (!of_node_cmp(np->name, info->desc.name)) { 383 + config->init_data = 384 + of_get_regulator_init_data(&pdev->dev, np); 385 + config->of_node = np; 386 + break; 387 + } 388 + } 389 + return 0; 390 + } 391 + #else 392 + #define pm8607_regulator_dt_init(x, y, z) (-1) 393 + #endif 394 + 369 395 static int __devinit pm8607_regulator_probe(struct platform_device *pdev) 370 396 { 371 397 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); ··· 432 402 info->slope_double = 1; 433 403 434 404 config.dev = &pdev->dev; 435 - config.init_data = pdata; 436 405 config.driver_data = info; 406 + 407 + if (pm8607_regulator_dt_init(pdev, info, &config)) 408 + if (pdata) 409 + config.init_data = pdata; 437 410 438 411 if (chip->id == CHIP_PM8607) 439 412 config.regmap = chip->regmap;
+34 -9
drivers/rtc/rtc-88pm860x.c
··· 11 11 12 12 #include <linux/kernel.h> 13 13 #include <linux/module.h> 14 + #include <linux/of.h> 14 15 #include <linux/platform_device.h> 15 16 #include <linux/slab.h> 16 17 #include <linux/mutex.h> ··· 285 284 } 286 285 #endif 287 286 287 + #ifdef CONFIG_OF 288 + static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev, 289 + struct pm860x_rtc_info *info) 290 + { 291 + struct device_node *np = pdev->dev.parent->of_node; 292 + int ret; 293 + if (!np) 294 + return -ENODEV; 295 + np = of_find_node_by_name(np, "rtc"); 296 + if (!np) { 297 + dev_err(&pdev->dev, "failed to find rtc node\n"); 298 + return -ENODEV; 299 + } 300 + ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc); 301 + if (ret) 302 + info->vrtc = 0; 303 + return 0; 304 + } 305 + #else 306 + #define pm860x_rtc_dt_init(x, y) (-1) 307 + #endif 308 + 288 309 static int __devinit pm860x_rtc_probe(struct platform_device *pdev) 289 310 { 290 311 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); ··· 317 294 int ret; 318 295 319 296 pdata = pdev->dev.platform_data; 320 - if (pdata == NULL) 321 - dev_warn(&pdev->dev, "No platform data!\n"); 322 297 323 298 info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); 324 299 if (!info) ··· 366 345 } 367 346 } 368 347 rtc_tm_to_time(&tm, &ticks); 369 - if (pdata && pdata->sync) { 370 - pdata->sync(ticks); 371 - info->sync = pdata->sync; 348 + if (pm860x_rtc_dt_init(pdev, info)) { 349 + if (pdata && pdata->sync) { 350 + pdata->sync(ticks); 351 + info->sync = pdata->sync; 352 + } 372 353 } 373 354 374 355 info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, ··· 389 366 390 367 #ifdef VRTC_CALIBRATION 391 368 /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ 392 - if (pdata && pdata->vrtc) 393 - info->vrtc = pdata->vrtc & 0x3; 394 - else 395 - info->vrtc = 1; 369 + if (pm860x_rtc_dt_init(pdev, info)) { 370 + if (pdata && pdata->vrtc) 371 + info->vrtc = pdata->vrtc & 0x3; 372 + else 373 + info->vrtc = 1; 374 + } 396 375 pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); 397 376 398 377 /* calibrate VRTC */
+36 -3
drivers/video/backlight/88pm860x_bl.c
··· 11 11 12 12 #include <linux/init.h> 13 13 #include <linux/kernel.h> 14 + #include <linux/of.h> 14 15 #include <linux/platform_device.h> 15 16 #include <linux/slab.h> 16 17 #include <linux/fb.h> ··· 160 159 .get_brightness = pm860x_backlight_get_brightness, 161 160 }; 162 161 162 + #ifdef CONFIG_OF 163 + static int pm860x_backlight_dt_init(struct platform_device *pdev, 164 + struct pm860x_backlight_data *data, 165 + char *name) 166 + { 167 + struct device_node *nproot = pdev->dev.parent->of_node, *np; 168 + int iset = 0; 169 + if (!nproot) 170 + return -ENODEV; 171 + nproot = of_find_node_by_name(nproot, "backlights"); 172 + if (!nproot) { 173 + dev_err(&pdev->dev, "failed to find backlights node\n"); 174 + return -ENODEV; 175 + } 176 + for_each_child_of_node(nproot, np) { 177 + if (!of_node_cmp(np->name, name)) { 178 + of_property_read_u32(np, "marvell,88pm860x-iset", 179 + &iset); 180 + data->iset = PM8606_WLED_CURRENT(iset); 181 + of_property_read_u32(np, "marvell,88pm860x-pwm", 182 + &data->pwm); 183 + break; 184 + } 185 + } 186 + return 0; 187 + } 188 + #else 189 + #define pm860x_backlight_dt_init(x, y, z) (-1) 190 + #endif 191 + 163 192 static int pm860x_backlight_probe(struct platform_device *pdev) 164 193 { 165 194 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); ··· 234 203 data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ 235 204 : chip->companion; 236 205 data->current_brightness = MAX_BRIGHTNESS; 237 - if (pdata) { 238 - data->pwm = pdata->pwm; 239 - data->iset = pdata->iset; 206 + if (pm860x_backlight_dt_init(pdev, data, name)) { 207 + if (pdata) { 208 + data->pwm = pdata->pwm; 209 + data->iset = pdata->iset; 210 + } 240 211 } 241 212 242 213 memset(&props, 0, sizeof(struct backlight_properties));
+2 -2
include/linux/mfd/88pm860x.h
··· 306 306 struct regmap *regmap_companion; 307 307 308 308 int buck3_double; /* DVC ramp slope double */ 309 - unsigned short companion_addr; 309 + int companion_addr; 310 310 unsigned short osc_vote; 311 311 int id; 312 312 int irq_mode; ··· 376 376 struct regulator_init_data *ldo_vibrator; 377 377 struct regulator_init_data *ldo14; 378 378 379 - unsigned short companion_addr; /* I2C address of companion chip */ 379 + int companion_addr; /* I2C address of companion chip */ 380 380 int i2c_port; /* Controlled by GI2C or PI2C */ 381 381 int irq_mode; /* Clear interrupt by read/write(0/1) */ 382 382 int irq_base; /* IRQ base number of 88pm860x */