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/video/backlight/max8925_bl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') 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/video/backlight/88pm860x_bl.c | 114 ++++++++++++++-------------------- 1 file changed, 46 insertions(+), 68 deletions(-) (limited to 'drivers/video') 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; } -- 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/video/backlight/max8925_bl.c | 79 +++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 38 deletions(-) (limited to 'drivers/video') 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 ++++++++++++++++++++++++++++++++++ 3 files changed, 360 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 "); -- 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 --- drivers/video/backlight/88pm860x_bl.c | 39 ++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'drivers/video') 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)); -- cgit v1.2.3