From 023670295ab6b65f5a84b8f214377c04c683809d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:48 +0100 Subject: mfd: 88pm860x: Convert to IORESOURCE_REG Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/video/backlight/88pm860x_bl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index f75da8758adc..d65472e9b30d 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -201,7 +201,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) char name[MFD_NAME_SIZE]; int ret; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; -- cgit v1.2.3 From 015625a20f630c798a8c5fdf5d472be091b8ac7d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:49 +0100 Subject: mfd: max8925: Convert to IORESOURCE_REG Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 18 ++++-------------- drivers/video/backlight/max8925_bl.c | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/video') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 6aa3a22ea435..08a57231c25b 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -18,19 +18,12 @@ #include #include -static struct resource io_parent = { - .start = 0, - .end = 0xffffffff, - .flags = IORESOURCE_IO, -}; - static struct resource backlight_resources[] = { { .name = "max8925-backlight", .start = MAX8925_WLED_MODE_CNTL, .end = MAX8925_WLED_CNTL, - .flags = IORESOURCE_IO, - .parent = &io_parent, + .flags = IORESOURCE_REG, }, }; @@ -48,8 +41,7 @@ static struct resource touch_resources[] = { .name = "max8925-tsc", .start = MAX8925_TSC_IRQ, .end = MAX8925_ADC_RES_END, - .flags = IORESOURCE_IO, - .parent = &io_parent, + .flags = IORESOURCE_REG, }, }; @@ -67,8 +59,7 @@ static struct resource power_supply_resources[] = { .name = "max8925-power", .start = MAX8925_CHG_IRQ1, .end = MAX8925_CHG_IRQ1_MASK, - .flags = IORESOURCE_IO, - .parent = &io_parent, + .flags = IORESOURCE_REG, }, }; @@ -126,8 +117,7 @@ static struct mfd_cell onkey_devs[] = { { \ .start = MAX8925_##_start, \ .end = MAX8925_##_end, \ - .flags = IORESOURCE_IO, \ - .parent = &io_parent, \ + .flags = IORESOURCE_REG, \ } static struct resource regulator_resources[] = { diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index e833ac72e063..996dadfa09ff 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -112,7 +112,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) unsigned char value; int ret; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; -- cgit v1.2.3 From a6ccdcd98c39ac13508570dbd943a1cf1b569f55 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 8 Aug 2012 23:17:26 +0800 Subject: mfd: 88pm860x: Use REG resource for backlight Now resource of 88pm860x backlight is changed from IORESOURCE_IO to IORESOURCE_REG. In original driver, the resource is using self-defined IORESOURCE_IO. So change the resource to register offset to match the definition of IORESOURCE_REG. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 78 ++++++++++++----------- drivers/video/backlight/88pm860x_bl.c | 114 ++++++++++++++-------------------- include/linux/mfd/88pm860x.h | 8 --- 3 files changed, 89 insertions(+), 111 deletions(-) (limited to 'drivers/video') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 75864383573d..b72628e8d6ee 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -21,10 +21,20 @@ #define INT_STATUS_NUM 3 -static struct resource bk_resources[] __devinitdata = { - {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_REG,}, - {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_REG,}, - {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_REG,}, +static struct resource bk0_resources[] __devinitdata = { + {2, 2, "duty cycle", IORESOURCE_REG, }, + {3, 3, "always on", IORESOURCE_REG, }, + {3, 3, "current", IORESOURCE_REG, }, +}; +static struct resource bk1_resources[] __devinitdata = { + {4, 4, "duty cycle", IORESOURCE_REG, }, + {5, 5, "always on", IORESOURCE_REG, }, + {5, 5, "current", IORESOURCE_REG, }, +}; +static struct resource bk2_resources[] __devinitdata = { + {6, 6, "duty cycle", IORESOURCE_REG, }, + {7, 7, "always on", IORESOURCE_REG, }, + {5, 5, "current", IORESOURCE_REG, }, }; static struct resource led_resources[] __devinitdata = { @@ -99,9 +109,22 @@ static struct resource rtc_resources[] __devinitdata = { }; static struct mfd_cell bk_devs[] = { - {"88pm860x-backlight", 0,}, - {"88pm860x-backlight", 1,}, - {"88pm860x-backlight", 2,}, + { + .name = "88pm860x-backlight", + .id = 0, + .num_resources = ARRAY_SIZE(bk0_resources), + .resources = bk0_resources, + }, { + .name = "88pm860x-backlight", + .id = 1, + .num_resources = ARRAY_SIZE(bk1_resources), + .resources = bk1_resources, + }, { + .name = "88pm860x-backlight", + .id = 2, + .num_resources = ARRAY_SIZE(bk2_resources), + .resources = bk2_resources, + }, }; static struct mfd_cell led_devs[] = { @@ -615,36 +638,21 @@ static void __devinit device_osc_init(struct i2c_client *i2c) static void __devinit device_bk_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - int ret; - int i, j, id; - - if ((pdata == NULL) || (pdata->backlight == NULL)) - return; - - if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) - pdata->num_backlights = ARRAY_SIZE(bk_devs); - - for (i = 0; i < pdata->num_backlights; i++) { - bk_devs[i].platform_data = &pdata->backlight[i]; - bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); - - for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { - id = bk_resources[j].start; - if (pdata->backlight[i].flags != id) - continue; - - bk_devs[i].num_resources = 1; - bk_devs[i].resources = &bk_resources[j]; - ret = mfd_add_devices(chip->dev, 0, - &bk_devs[i], 1, - &bk_resources[j], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add " - "backlight subdev\n"); - return; - } + int ret, i; + + if (pdata && pdata->backlight) { + if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) + pdata->num_backlights = ARRAY_SIZE(bk_devs); + for (i = 0; i < pdata->num_backlights; i++) { + bk_devs[i].platform_data = &pdata->backlight[i]; + bk_devs[i].pdata_size = + sizeof(struct pm860x_backlight_pdata); } } + ret = mfd_add_devices(chip->dev, 0, bk_devs, + ARRAY_SIZE(bk_devs), NULL, 0); + if (ret < 0) + dev_err(chip->dev, "Failed to add backlight subdev\n"); } static void __devinit device_led_init(struct pm860x_chip *chip, diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index d65472e9b30d..965161cacefa 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -31,57 +31,26 @@ struct pm860x_backlight_data { int port; int pwm; int iset; + int reg_duty_cycle; + int reg_always_on; + int reg_current; }; -static inline int wled_a(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 2; - return ret; -} - -static inline int wled_b(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - return ret; -} - -/* WLED2 & WLED3 share the same IDC */ -static inline int wled_idc(int port) -{ - int ret; - - switch (port) { - case PM8606_BACKLIGHT1: - case PM8606_BACKLIGHT2: - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - break; - case PM8606_BACKLIGHT3: - default: - ret = ((port - PM8606_BACKLIGHT2) << 1) + 3; - break; - } - return ret; -} - static int backlight_power_set(struct pm860x_chip *chip, int port, int on) { int ret = -EINVAL; switch (port) { - case PM8606_BACKLIGHT1: + case 0: ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) : pm8606_osc_disable(chip, WLED1_DUTY); break; - case PM8606_BACKLIGHT2: + case 1: ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) : pm8606_osc_disable(chip, WLED2_DUTY); break; - case PM8606_BACKLIGHT3: + case 2: ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) : pm8606_osc_disable(chip, WLED3_DUTY); break; @@ -104,13 +73,13 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) if (brightness) backlight_power_set(chip, data->port, 1); - ret = pm860x_reg_write(data->i2c, wled_a(data->port), value); + ret = pm860x_reg_write(data->i2c, data->reg_duty_cycle, value); if (ret < 0) goto out; if ((data->current_brightness == 0) && brightness) { if (data->iset) { - ret = pm860x_set_bits(data->i2c, wled_idc(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_current, CURRENT_BITMASK, data->iset); if (ret < 0) goto out; @@ -123,17 +92,17 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) } if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } } else { if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } else { /* clear WLED_ON bit since it's not 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, 0); } } @@ -174,7 +143,7 @@ static int pm860x_backlight_get_brightness(struct backlight_device *bl) struct pm860x_chip *chip = data->chip; int ret; - ret = pm860x_reg_read(data->i2c, wled_a(data->port)); + ret = pm860x_reg_read(data->i2c, data->reg_duty_cycle); if (ret < 0) goto out; data->current_brightness = ret; @@ -193,43 +162,50 @@ static const struct backlight_ops pm860x_backlight_ops = { static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_backlight_pdata *pdata = NULL; + struct pm860x_backlight_pdata *pdata = pdev->dev.platform_data; struct pm860x_backlight_data *data; struct backlight_device *bl; struct resource *res; struct backlight_properties props; char name[MFD_NAME_SIZE]; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MFD_NAME_SIZE); + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "duty cycle"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for duty cycle\n"); + ret = -ENXIO; + goto out; + } + data->reg_duty_cycle = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "always on"); + if (!res) { + dev_err(&pdev->dev, "No REG resorce for always on\n"); + ret = -ENXIO; + goto out; + } + data->reg_always_on = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "current"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for current\n"); + ret = -ENXIO; + goto out; + } + data->reg_current = res->start; + + memset(name, 0, MFD_NAME_SIZE); + sprintf(name, "backlight-%d", pdev->id); + data->port = pdev->id; data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; - data->pwm = pdata->pwm; - data->iset = pdata->iset; - data->port = pdata->flags; - if (data->port < 0) { - dev_err(&pdev->dev, "wrong platform data is assigned"); - kfree(data); - return -EINVAL; + if (pdata) { + data->pwm = pdata->pwm; + data->iset = pdata->iset; } memset(&props, 0, sizeof(struct backlight_properties)); @@ -248,12 +224,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev) /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index 7b24943779fa..b7e656d29be3 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -34,12 +34,6 @@ enum { PM8606_ID_MAX, }; -enum { - PM8606_BACKLIGHT1 = 0, - PM8606_BACKLIGHT2, - PM8606_BACKLIGHT3, -}; - enum { PM8606_LED1_RED = 0, PM8606_LED1_GREEN, @@ -340,10 +334,8 @@ enum { }; struct pm860x_backlight_pdata { - int id; int pwm; int iset; - unsigned long flags; }; struct pm860x_led_pdata { -- cgit v1.2.3 From 63b501e22aa9b22cdfe206a5670aaae646d93021 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 17 Sep 2012 12:19:04 +0800 Subject: mfd: max8925: Use register offset as REG in backlight Remove the register offset definition. All these register offset are transfered as IORESOURCE_REG resources. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 31 +++++++------- drivers/video/backlight/max8925_bl.c | 79 +++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 55 deletions(-) (limited to 'drivers/video') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index e25a24269d51..934be40cd542 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -18,20 +18,16 @@ #include #include -static struct resource backlight_resources[] = { - { - .name = "max8925-backlight", - .start = MAX8925_WLED_MODE_CNTL, - .end = MAX8925_WLED_CNTL, - .flags = IORESOURCE_REG, - }, +static struct resource bk_resources[] __devinitdata = { + { 0x84, 0x84, "mode control", IORESOURCE_REG, }, + { 0x85, 0x85, "control", IORESOURCE_REG, }, }; -static struct mfd_cell backlight_devs[] = { +static struct mfd_cell bk_devs[] __devinitdata = { { .name = "max8925-backlight", - .num_resources = 1, - .resources = &backlight_resources[0], + .num_resources = ARRAY_SIZE(bk_resources), + .resources = &bk_resources[0], .id = -1, }, }; @@ -623,13 +619,14 @@ int __devinit max8925_device_init(struct max8925_chip *chip, } if (pdata && pdata->backlight) { - ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], - ARRAY_SIZE(backlight_devs), - &backlight_resources[0], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add backlight subdev\n"); - goto out_dev; - } + bk_devs[0].platform_data = &pdata->backlight; + bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata); + } + ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs), + NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add backlight subdev\n"); + goto out_dev; } if (pdata && pdata->power) { diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 996dadfa09ff..f72ba54f364e 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -27,7 +27,9 @@ struct max8925_backlight_data { struct max8925_chip *chip; - int current_brightness; + int current_brightness; + int reg_mode_cntl; + int reg_cntl; }; static int max8925_backlight_set(struct backlight_device *bl, int brightness) @@ -42,16 +44,16 @@ static int max8925_backlight_set(struct backlight_device *bl, int brightness) else value = brightness; - ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value); + ret = max8925_reg_write(chip->i2c, data->reg_cntl, value); if (ret < 0) goto out; if (!data->current_brightness && brightness) /* enable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1); else if (!brightness) /* disable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0); if (ret < 0) goto out; dev_dbg(chip->dev, "set brightness %d\n", value); @@ -85,7 +87,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl) struct max8925_chip *chip = data->chip; int ret; - ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL); + ret = max8925_reg_read(chip->i2c, data->reg_cntl); if (ret < 0) return -EINVAL; data->current_brightness = ret; @@ -102,69 +104,70 @@ static const struct backlight_ops max8925_backlight_ops = { static int __devinit max8925_backlight_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *max8925_pdata; - struct max8925_backlight_pdata *pdata = NULL; + struct max8925_backlight_pdata *pdata = pdev->dev.platform_data; struct max8925_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; struct resource *res; - char name[MAX8925_NAME_SIZE]; unsigned char value; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - if (pdev->dev.parent->platform_data) { - max8925_pdata = pdev->dev.parent->platform_data; - pdata = max8925_pdata->backlight; - } - - if (!pdata) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MAX8925_NAME_SIZE); + + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (!res) { + dev_err(&pdev->dev, "No REG resource for mode control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_mode_cntl = res->start; + res = platform_get_resource(pdev, IORESOURCE_REG, 1); + if (!res) { + dev_err(&pdev->dev, "No REG resource for control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_cntl = res->start; + data->chip = chip; data->current_brightness = 0; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register(name, &pdev->dev, data, + bl = backlight_device_register("max8925-backlight", &pdev->dev, data, &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - return PTR_ERR(bl); + ret = PTR_ERR(bl); + goto out; } bl->props.brightness = MAX_BRIGHTNESS; platform_set_drvdata(pdev, bl); value = 0; - if (pdata->lxw_scl) - value |= (1 << 7); - if (pdata->lxw_freq) - value |= (LWX_FREQ(pdata->lxw_freq) << 4); - if (pdata->dual_string) - value |= (1 << 1); - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value); + if (pdata) { + if (pdata->lxw_scl) + value |= (1 << 7); + if (pdata->lxw_freq) + value |= (LWX_FREQ(pdata->lxw_freq) << 4); + if (pdata->dual_string) + value |= (1 << 1); + } + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } -- cgit v1.2.3 From eebfdc17cc6c9f184a713d84b84e7602236360c6 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 24 Sep 2012 22:25:28 +0200 Subject: backlight: Add TPS65217 WLED driver The TPS65217 chip contains a boost converter and current sinks which can be used to drive LEDs for use as backlights. Expose this functionality via the backlight API. Tested on an AM335x based custom board with a single WLED string, using different values for ISEL and FDIM (though it would be hard to tell the difference except for the value in WLEDCTRL1). Both instantiation through the device tree and by passing platform data have been tested. Testing has been done with an Androidized 3.2 kernel from the rowboat project. Koen Kooi reported the driver to be working on a Beaglebone board with LCD3 cape Signed-off-by: Matthias Kaehlcke Signed-off-by: Samuel Ortiz --- drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/tps65217_bl.c | 352 ++++++++++++++++++++++++++++++++++ include/linux/mfd/tps65217.h | 18 ++ 4 files changed, 378 insertions(+) create mode 100644 drivers/video/backlight/tps65217_bl.c (limited to 'drivers/video') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index cf282763a8dc..63cee2e9d622 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -373,6 +373,13 @@ config BACKLIGHT_PANDORA If you have a Pandora console, say Y to enable the backlight driver. +config BACKLIGHT_TPS65217 + tristate "TPS65217 Backlight" + depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 + help + If you have a Texas Instruments TPS65217 say Y to enable the + backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index a2ac9cfbaf6b..00223a62ec12 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o +obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c new file mode 100644 index 000000000000..6ac2ef5da32c --- /dev/null +++ b/drivers/video/backlight/tps65217_bl.c @@ -0,0 +1,352 @@ +/* + * tps65217_bl.c + * + * TPS65217 backlight driver + * + * Copyright (C) 2012 Matthias Kaehlcke + * Author: Matthias Kaehlcke + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct tps65217_bl { + struct tps65217 *tps; + struct device *dev; + struct backlight_device *bl; + bool is_enabled; +}; + +static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to enable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = true; + + dev_dbg(tps65217_bl->dev, "backlight enabled\n"); + + return 0; +} + +static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to disable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = false; + + dev_dbg(tps65217_bl->dev, "backlight disabled\n"); + + return 0; +} + +static int tps65217_bl_update_status(struct backlight_device *bl) +{ + struct tps65217_bl *tps65217_bl = bl_get_data(bl); + int rc; + int brightness = bl->props.brightness; + + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + if ((bl->props.power != FB_BLANK_UNBLANK) || + (bl->props.fb_blank != FB_BLANK_UNBLANK)) + /* framebuffer in low power mode or blanking active */ + brightness = 0; + + if (brightness > 0) { + rc = tps65217_reg_write(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL2, + brightness - 1, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to set brightness level: %d\n", rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness); + + if (!tps65217_bl->is_enabled) + rc = tps65217_bl_enable(tps65217_bl); + } else { + rc = tps65217_bl_disable(tps65217_bl); + } + + return rc; +} + +static int tps65217_bl_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static const struct backlight_ops tps65217_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = tps65217_bl_update_status, + .get_brightness = tps65217_bl_get_brightness +}; + +static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl, + struct tps65217_bl_pdata *pdata) +{ + int rc; + + rc = tps65217_bl_disable(tps65217_bl); + if (rc) + return rc; + + switch (pdata->isel) { + case TPS65217_BL_ISET1: + /* select ISET_1 current level */ + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET1 current level: %d)\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n"); + + break; + + case TPS65217_BL_ISET2: + /* select ISET2 current level */ + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET2 current level: %d\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n"); + + break; + + default: + dev_err(tps65217_bl->dev, + "invalid value for current level: %d\n", pdata->isel); + return -EINVAL; + } + + /* set PWM frequency */ + rc = tps65217_set_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_FDIM_MASK, + pdata->fdim, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select PWM dimming frequency: %d\n", + rc); + return rc; + } + + return 0; +} + +#ifdef CONFIG_OF +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct device_node *node = of_node_get(tps->dev->of_node); + struct tps65217_bl_pdata *pdata, *err; + u32 val; + + node = of_find_node_by_name(node, "backlight"); + if (!node) + return ERR_PTR(-ENODEV); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "failed to allocate platform data\n"); + err = ERR_PTR(-ENOMEM); + goto err; + } + + pdata->isel = TPS65217_BL_ISET1; + if (!of_property_read_u32(node, "isel", &val)) { + if (val < TPS65217_BL_ISET1 || + val > TPS65217_BL_ISET2) { + dev_err(&pdev->dev, + "invalid 'isel' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + + pdata->isel = val; + } + + pdata->fdim = TPS65217_BL_FDIM_200HZ; + if (!of_property_read_u32(node, "fdim", &val)) { + switch (val) { + case 100: + pdata->fdim = TPS65217_BL_FDIM_100HZ; + break; + + case 200: + pdata->fdim = TPS65217_BL_FDIM_200HZ; + break; + + case 500: + pdata->fdim = TPS65217_BL_FDIM_500HZ; + break; + + case 1000: + pdata->fdim = TPS65217_BL_FDIM_1000HZ; + break; + + default: + dev_err(&pdev->dev, + "invalid 'fdim' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + } + + of_node_put(node); + + return pdata; + +err: + of_node_put(node); + + return err; +} +#else +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +#endif + +static int tps65217_bl_probe(struct platform_device *pdev) +{ + int rc; + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct tps65217_bl *tps65217_bl; + struct tps65217_bl_pdata *pdata; + struct backlight_properties bl_props; + + if (tps->dev->of_node) { + pdata = tps65217_bl_parse_dt(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } else { + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + pdata = pdev->dev.platform_data; + } + + tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), + GFP_KERNEL); + if (tps65217_bl == NULL) { + dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n"); + return -ENOMEM; + } + + tps65217_bl->tps = tps; + tps65217_bl->dev = &pdev->dev; + tps65217_bl->is_enabled = false; + + rc = tps65217_bl_hw_init(tps65217_bl, pdata); + if (rc) + return rc; + + memset(&bl_props, 0, sizeof(struct backlight_properties)); + bl_props.type = BACKLIGHT_RAW; + bl_props.max_brightness = 100; + + tps65217_bl->bl = backlight_device_register(pdev->name, + tps65217_bl->dev, tps65217_bl, + &tps65217_bl_ops, &bl_props); + if (IS_ERR(tps65217_bl->bl)) { + dev_err(tps65217_bl->dev, + "registration of backlight device failed: %d\n", rc); + return PTR_ERR(tps65217_bl->bl); + } + + tps65217_bl->bl->props.brightness = 0; + + return 0; +} + +static int tps65217_bl_remove(struct platform_device *pdev) +{ + struct tps65217_bl *tps65217_bl = platform_get_drvdata(pdev); + + backlight_device_unregister(tps65217_bl->bl); + + return 0; +} + +static struct platform_driver tps65217_bl_driver = { + .probe = tps65217_bl_probe, + .remove = tps65217_bl_remove, + .driver = { + .owner = THIS_MODULE, + .name = "tps65217-bl", + }, +}; + +static int __init tps65217_bl_init(void) +{ + return platform_driver_register(&tps65217_bl_driver); +} + +static void __exit tps65217_bl_exit(void) +{ + platform_driver_unregister(&tps65217_bl_driver); +} + +module_init(tps65217_bl_init); +module_exit(tps65217_bl_exit); + +MODULE_DESCRIPTION("TPS65217 Backlight driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Matthias Kaehlcke "); diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index 7cd83d826ed8..290762f93930 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -213,6 +213,23 @@ enum tps65217_regulator_id { /* Number of total regulators available */ #define TPS65217_NUM_REGULATOR (TPS65217_NUM_DCDC + TPS65217_NUM_LDO) +enum tps65217_bl_isel { + TPS65217_BL_ISET1 = 1, + TPS65217_BL_ISET2, +}; + +enum tps65217_bl_fdim { + TPS65217_BL_FDIM_100HZ, + TPS65217_BL_FDIM_200HZ, + TPS65217_BL_FDIM_500HZ, + TPS65217_BL_FDIM_1000HZ, +}; + +struct tps65217_bl_pdata { + enum tps65217_bl_isel isel; + enum tps65217_bl_fdim fdim; +}; + /** * struct tps65217_board - packages regulator init data * @tps65217_regulator_data: regulator initialization values @@ -222,6 +239,7 @@ enum tps65217_regulator_id { struct tps65217_board { struct regulator_init_data *tps65217_init_data[TPS65217_NUM_REGULATOR]; struct device_node *of_node[TPS65217_NUM_REGULATOR]; + struct tps65217_bl_pdata *bl_pdata; }; /** -- cgit v1.2.3 From c6bed9deb6047179a6c58ace847f8b2129085e37 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Sep 2012 18:28:26 +0800 Subject: backlight: tps65217_bl: Add missing platform_set_drvdata in tps65217_bl_probe Otherwise, we got NULL derefernce while calling backlight_device_unregister() in tps65217_bl_remove(). Also convert to use module_platform_driver. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/video/backlight/tps65217_bl.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 6ac2ef5da32c..70881633b45a 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -312,6 +312,7 @@ static int tps65217_bl_probe(struct platform_device *pdev) } tps65217_bl->bl->props.brightness = 0; + platform_set_drvdata(pdev, tps65217_bl); return 0; } @@ -334,18 +335,7 @@ static struct platform_driver tps65217_bl_driver = { }, }; -static int __init tps65217_bl_init(void) -{ - return platform_driver_register(&tps65217_bl_driver); -} - -static void __exit tps65217_bl_exit(void) -{ - platform_driver_unregister(&tps65217_bl_driver); -} - -module_init(tps65217_bl_init); -module_exit(tps65217_bl_exit); +module_platform_driver(tps65217_bl_driver); MODULE_DESCRIPTION("TPS65217 Backlight driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2e57d56747e601b3e0ff6697e524025d0504d161 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 21 Sep 2012 18:06:52 +0800 Subject: mfd: 88pm860x: Device tree support Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/88pm860x.txt | 85 ++++++++++++++++++++++ .../devicetree/bindings/regulator/88pm860x.txt | 30 ++++++++ .../bindings/video/backlight/88pm860x.txt | 15 ++++ drivers/input/touchscreen/88pm860x-ts.c | 46 ++++++++---- drivers/leds/leds-88pm860x.c | 33 ++++++++- drivers/mfd/88pm860x-core.c | 62 +++++++++++++--- drivers/regulator/88pm8607.c | 35 ++++++++- drivers/rtc/rtc-88pm860x.c | 43 ++++++++--- drivers/video/backlight/88pm860x_bl.c | 39 +++++++++- include/linux/mfd/88pm860x.h | 4 +- 10 files changed, 351 insertions(+), 41 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/88pm860x.txt create mode 100644 Documentation/devicetree/bindings/regulator/88pm860x.txt create mode 100644 Documentation/devicetree/bindings/video/backlight/88pm860x.txt (limited to 'drivers/video') diff --git a/Documentation/devicetree/bindings/mfd/88pm860x.txt b/Documentation/devicetree/bindings/mfd/88pm860x.txt new file mode 100644 index 000000000000..63f3ee33759c --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/88pm860x.txt @@ -0,0 +1,85 @@ +* Marvell 88PM860x Power Management IC + +Required parent device properties: +- compatible : "marvell,88pm860x" +- reg : the I2C slave address for the 88pm860x chip +- interrupts : IRQ line for the 88pm860x chip +- interrupt-controller: describes the 88pm860x as an interrupt controller (has its own domain) +- #interrupt-cells : should be 1. + - The cell is the 88pm860x local IRQ number + +Optional parent device properties: +- marvell,88pm860x-irq-read-clr: inicates whether interrupt status is cleared by read +- marvell,88pm860x-slave-addr: 88pm860x are two chips solution. stores the I2C address + of one chip, and this property stores the I2C address of + another chip. + +88pm860x consists of a large and varied group of sub-devices: + +Device Supply Names Description +------ ------------ ----------- +88pm860x-onkey : : On key +88pm860x-rtc : : RTC +88pm8607 : : Regulators +88pm860x-backlight : : Backlight +88pm860x-led : : Led +88pm860x-touch : : Touchscreen + +Example: + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + interrupts = <4>; + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <1>; + + marvell,88pm860x-irq-read-clr; + marvell,88pm860x-slave-addr = <0x11>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + LDO1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + rtc { + marvell,88pm860x-vrtc = <1>; + }; + touch { + marvell,88pm860x-gpadc-prebias = <1>; + marvell,88pm860x-gpadc-slot-cycle = <1>; + marvell,88pm860x-tsi-prebias = <6>; + marvell,88pm860x-pen-prebias = <16>; + marvell,88pm860x-pen-prechg = <2>; + marvell,88pm860x-resistor-X = <300>; + }; + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; + }; + leds { + led0-red { + marvell,88pm860x-iset = <12>; + }; + led0-green { + marvell,88pm860x-iset = <12>; + }; + led0-blue { + marvell,88pm860x-iset = <12>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/88pm860x.txt b/Documentation/devicetree/bindings/regulator/88pm860x.txt new file mode 100644 index 000000000000..1267b3e1a2cc --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/88pm860x.txt @@ -0,0 +1,30 @@ +Marvell 88PM860x regulator + +Required properties: +- compatible: "marvell,88pm860x" +- reg: I2C slave address +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the regulator-compatible + property, with valid values listed below. + +Example: + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + BUCK3 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/video/backlight/88pm860x.txt b/Documentation/devicetree/bindings/video/backlight/88pm860x.txt new file mode 100644 index 000000000000..261df2799315 --- /dev/null +++ b/Documentation/devicetree/bindings/video/backlight/88pm860x.txt @@ -0,0 +1,15 @@ +88pm860x-backlight bindings + +Optional properties: + - marvell,88pm860x-iset: Current supplies on backlight device. + - marvell,88pm860x-pwm: PWM frequency on backlight device. + +Example: + + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 05f30b73c3c3..4f81e6eb74b6 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -10,6 +10,7 @@ */ #include #include +#include #include #include #include @@ -113,14 +114,31 @@ static void pm860x_touch_close(struct input_dev *dev) pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0); } +#ifdef CONFIG_OF +static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, + int *res_x) +{ + struct device_node *np = pdev->dev.parent->of_node; + if (!np) + return -ENODEV; + np = of_find_node_by_name(np, "touch"); + if (!np) { + dev_err(&pdev->dev, "Can't find touch node\n"); + return -EINVAL; + } + of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); + return 0; +} +#else +#define pm860x_touch_dt_init(x, y) (-1) +#endif + static int __devinit pm860x_touch_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_platform_data *pm860x_pdata = \ - pdev->dev.parent->platform_data; - struct pm860x_touch_pdata *pdata = NULL; + struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; struct pm860x_touch *touch; - int irq, ret; + int irq, ret, res_x = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -128,15 +146,13 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) return -EINVAL; } - if (!pm860x_pdata) { - dev_err(&pdev->dev, "platform data is missing\n"); - return -EINVAL; - } - - pdata = pm860x_pdata->touch; - if (!pdata) { - dev_err(&pdev->dev, "touchscreen data is missing\n"); - return -EINVAL; + if (pm860x_touch_dt_init(pdev, &res_x)) { + if (pdata) + res_x = pdata->res_x; + else { + dev_err(&pdev->dev, "failed to get platform data\n"); + return -EINVAL; + } } touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); @@ -159,8 +175,8 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) touch->idev->close = pm860x_touch_close; touch->chip = chip; touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; - touch->irq = irq + chip->irq_base; - touch->res_x = pdata->res_x; + touch->irq = irq; + touch->res_x = res_x; input_set_drvdata(touch->idev, touch); ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 70232b1756f9..b7e8cc0957fc 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -123,6 +124,33 @@ static void pm860x_led_set(struct led_classdev *cdev, schedule_work(&data->work); } +#ifdef CONFIG_OF +static int pm860x_led_dt_init(struct platform_device *pdev, + struct pm860x_led *data) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "leds"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find leds node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, data->name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_LED_CURRENT(iset); + break; + } + } + return 0; +} +#else +#define pm860x_led_dt_init(x, y) (-1) +#endif + static int pm860x_led_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -179,8 +207,9 @@ static int pm860x_led_probe(struct platform_device *pdev) data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; data->port = pdev->id; - if (pdata && pdata->iset) - data->iset = pdata->iset; + if (pm860x_led_dt_init(pdev, data)) + if (pdata) + data->iset = pdata->iset; data->current_brightness = 0; data->cdev.name = data->name; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 5b56fe8250b4..fdaf6861ce95 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -1112,12 +1114,6 @@ static void __devexit pm860x_device_exit(struct pm860x_chip *chip) mfd_remove_devices(chip->dev); } -static const struct i2c_device_id pm860x_id_table[] = { - { "88PM860x", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, pm860x_id_table); - static int verify_addr(struct i2c_client *i2c) { unsigned short addr_8607[] = {0x30, 0x34}; @@ -1144,21 +1140,52 @@ static struct regmap_config pm860x_regmap_config = { .val_bits = 8, }; +static int __devinit pm860x_dt_init(struct device_node *np, + struct device *dev, + struct pm860x_platform_data *pdata) +{ + int ret; + + if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) + pdata->irq_mode = 1; + ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", + &pdata->companion_addr); + if (ret) { + dev_err(dev, "Not found \"marvell,88pm860x-slave-addr\" " + "property\n"); + pdata->companion_addr = 0; + } + return 0; +} + static int __devinit pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pm860x_platform_data *pdata = client->dev.platform_data; + struct device_node *node = client->dev.of_node; struct pm860x_chip *chip; int ret; - if (!pdata) { + if (node && !pdata) { + /* parse DT to get platform data */ + pdata = devm_kzalloc(&client->dev, + sizeof(struct pm860x_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + ret = pm860x_dt_init(node, &client->dev, pdata); + if (ret) + goto err; + } else if (!pdata) { pr_info("No platform data in %s!\n", __func__); return -EINVAL; } chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; + if (chip == NULL) { + ret = -ENOMEM; + goto err; + } chip->id = verify_addr(client); chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); @@ -1198,6 +1225,10 @@ static int __devinit pm860x_probe(struct i2c_client *client, pm860x_device_init(chip, pdata); return 0; +err: + if (node) + devm_kfree(&client->dev, pdata); + return ret; } static int __devexit pm860x_remove(struct i2c_client *client) @@ -1238,11 +1269,24 @@ static int pm860x_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); +static const struct i2c_device_id pm860x_id_table[] = { + { "88PM860x", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pm860x_id_table); + +static const struct of_device_id pm860x_dt_ids[] = { + { .compatible = "marvell,88pm860x", }, + {}, +}; +MODULE_DEVICE_TABLE(of, pm860x_dt_ids); + static struct i2c_driver pm860x_driver = { .driver = { .name = "88PM860x", .owner = THIS_MODULE, .pm = &pm860x_pm_ops, + .of_match_table = of_match_ptr(pm860x_dt_ids), }, .probe = pm860x_probe, .remove = __devexit_p(pm860x_remove), diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index f96fbe38ff6f..1c5ab0172ea2 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -364,6 +366,34 @@ static struct pm8607_regulator_info pm8606_regulator_info[] = { PM8606_PREG(PREREGULATORB, 5), }; +#ifdef CONFIG_OF +static int pm8607_regulator_dt_init(struct platform_device *pdev, + struct pm8607_regulator_info *info, + struct regulator_config *config) +{ + struct device_node *nproot, *np; + nproot = pdev->dev.parent->of_node; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "regulators"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find regulators node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, info->desc.name)) { + config->init_data = + of_get_regulator_init_data(&pdev->dev, np); + config->of_node = np; + break; + } + } + return 0; +} +#else +#define pm8607_regulator_dt_init(x, y, z) (-1) +#endif + static int __devinit pm8607_regulator_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -402,9 +432,12 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) info->slope_double = 1; config.dev = &pdev->dev; - config.init_data = pdata; config.driver_data = info; + if (pm8607_regulator_dt_init(pdev, info, &config)) + if (pdata) + config.init_data = pdata; + if (chip->id == CHIP_PM8607) config.regmap = chip->regmap; else diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index feddefc42109..de9e854b326a 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -284,6 +285,28 @@ out: } #endif +#ifdef CONFIG_OF +static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev, + struct pm860x_rtc_info *info) +{ + struct device_node *np = pdev->dev.parent->of_node; + int ret; + if (!np) + return -ENODEV; + np = of_find_node_by_name(np, "rtc"); + if (!np) { + dev_err(&pdev->dev, "failed to find rtc node\n"); + return -ENODEV; + } + ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc); + if (ret) + info->vrtc = 0; + return 0; +} +#else +#define pm860x_rtc_dt_init(x, y) (-1) +#endif + static int __devinit pm860x_rtc_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -294,8 +317,6 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) int ret; pdata = pdev->dev.platform_data; - if (pdata == NULL) - dev_warn(&pdev->dev, "No platform data!\n"); info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); if (!info) @@ -345,9 +366,11 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) } } rtc_tm_to_time(&tm, &ticks); - if (pdata && pdata->sync) { - pdata->sync(ticks); - info->sync = pdata->sync; + if (pm860x_rtc_dt_init(pdev, info)) { + if (pdata && pdata->sync) { + pdata->sync(ticks); + info->sync = pdata->sync; + } } info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, @@ -366,10 +389,12 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) #ifdef VRTC_CALIBRATION /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ - if (pdata && pdata->vrtc) - info->vrtc = pdata->vrtc & 0x3; - else - info->vrtc = 1; + if (pm860x_rtc_dt_init(pdev, info)) { + if (pdata && pdata->vrtc) + info->vrtc = pdata->vrtc & 0x3; + else + info->vrtc = 1; + } pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); /* calibrate VRTC */ diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 965161cacefa..b7ec34c57f46 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -159,6 +160,36 @@ static const struct backlight_ops pm860x_backlight_ops = { .get_brightness = pm860x_backlight_get_brightness, }; +#ifdef CONFIG_OF +static int pm860x_backlight_dt_init(struct platform_device *pdev, + struct pm860x_backlight_data *data, + char *name) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "backlights"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find backlights node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_WLED_CURRENT(iset); + of_property_read_u32(np, "marvell,88pm860x-pwm", + &data->pwm); + break; + } + } + return 0; +} +#else +#define pm860x_backlight_dt_init(x, y, z) (-1) +#endif + static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -203,9 +234,11 @@ static int pm860x_backlight_probe(struct platform_device *pdev) data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; - if (pdata) { - data->pwm = pdata->pwm; - data->iset = pdata->iset; + if (pm860x_backlight_dt_init(pdev, data, name)) { + if (pdata) { + data->pwm = pdata->pwm; + data->iset = pdata->iset; + } } memset(&props, 0, sizeof(struct backlight_properties)); diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index d515e5c438f0..ef3e6b701179 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -306,7 +306,7 @@ struct pm860x_chip { struct regmap *regmap_companion; int buck3_double; /* DVC ramp slope double */ - unsigned short companion_addr; + int companion_addr; unsigned short osc_vote; int id; int irq_mode; @@ -376,7 +376,7 @@ struct pm860x_platform_data { struct regulator_init_data *ldo_vibrator; struct regulator_init_data *ldo14; - unsigned short companion_addr; /* I2C address of companion chip */ + int companion_addr; /* I2C address of companion chip */ int i2c_port; /* Controlled by GI2C or PI2C */ int irq_mode; /* Clear interrupt by read/write(0/1) */ int irq_base; /* IRQ base number of 88pm860x */ -- cgit v1.2.3