diff options
Diffstat (limited to 'drivers/video/backlight')
57 files changed, 6246 insertions, 1794 deletions
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index f49181c7311..7db5234462d 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/fb.h> @@ -31,57 +32,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 +74,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 +93,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); } } @@ -147,8 +117,8 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) data->current_brightness = value; return 0; out: - dev_dbg(chip->dev, "set brightness %d failure with return " - "value:%d\n", value, ret); + dev_dbg(chip->dev, "set brightness %d failure with return value: %d\n", + value, ret); return ret; } @@ -174,7 +144,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; @@ -190,51 +160,90 @@ 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, *np; + int iset = 0; + + nproot = of_node_get(pdev->dev.parent->of_node); + 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; + } + } + of_node_put(nproot); + 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); - struct pm860x_backlight_pdata *pdata = NULL; + struct pm860x_backlight_pdata *pdata = dev_get_platdata(&pdev->dev); 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_IO, 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"); + return -ENXIO; + } + 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"); + return -ENXIO; + } + 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"); + return -ENXIO; + } + 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->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"); - return -EINVAL; + 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)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register(name, &pdev->dev, data, + bl = devm_backlight_device_register(&pdev->dev, name, &pdev->dev, data, &pm860x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); @@ -247,21 +256,10 @@ static int pm860x_backlight_probe(struct platform_device *pdev) /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) - goto out; + return ret; backlight_update_status(bl); return 0; -out: - backlight_device_unregister(bl); - return ret; -} - -static int pm860x_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; } static struct platform_driver pm860x_backlight_driver = { @@ -270,7 +268,6 @@ static struct platform_driver pm860x_backlight_driver = { .owner = THIS_MODULE, }, .probe = pm860x_backlight_probe, - .remove = pm860x_backlight_remove, }; module_platform_driver(pm860x_backlight_driver); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2979292650d..5d449059a55 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -29,21 +29,21 @@ if LCD_CLASS_DEVICE config LCD_CORGI tristate "LCD Panel support for SHARP corgi/spitz model" - depends on SPI_MASTER && PXA_SHARPSL + depends on SPI_MASTER && PXA_SHARPSL && BACKLIGHT_CLASS_DEVICE help Say y here to support the LCD panels usually found on SHARP corgi (C7x0) and spitz (Cxx00) models. config LCD_L4F00242T03 tristate "Epson L4F00242T03 LCD" - depends on SPI_MASTER && GENERIC_GPIO + depends on SPI_MASTER && GPIOLIB help SPI driver for Epson L4F00242T03. This provides basic support for init and powering the LCD up/down through a sysfs interface. config LCD_LMS283GF05 tristate "Samsung LMS283GF05 LCD" - depends on SPI_MASTER && GENERIC_GPIO + depends on SPI_MASTER && GPIOLIB help SPI driver for Samsung LMS283GF05. This provides basic support for powering the LCD up/down through a sysfs interface. @@ -59,8 +59,16 @@ config LCD_LTV350QV The LTV350QV panel is present on all ATSTK1000 boards. +config LCD_ILI922X + tristate "ILI Technology ILI9221/ILI9222 support" + depends on SPI + help + If you have a panel based on the ILI9221/9222 controller + chip then say y to include a driver for it. + config LCD_ILI9320 - tristate + tristate "ILI Technology ILI9320 controller support" + depends on SPI help If you have a panel based on the ILI9320 controller chip then say y to include a power driver for it. @@ -125,6 +133,21 @@ config LCD_AMS369FG06 If you have an AMS369FG06 AMOLED Panel, say Y to enable its LCD control driver. +config LCD_LMS501KF03 + tristate "LMS501KF03 LCD Driver" + depends on SPI + default n + help + If you have an LMS501KF03 LCD Panel, say Y to enable its + LCD control driver. + +config LCD_HX8357 + tristate "Himax HX-8357 LCD Driver" + depends on SPI + help + If you have a HX-8357 LCD panel, say Y to enable its LCD control + driver. + endif # LCD_CLASS_DEVICE # @@ -145,7 +168,7 @@ if BACKLIGHT_CLASS_DEVICE config BACKLIGHT_ATMEL_LCDC bool "Atmel LCDC Contrast-as-Backlight control" depends on FB_ATMEL - default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK + default y if MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK help This provides a backlight control internal to the Atmel LCDC driver. If the LCD "contrast control" on your board is wired @@ -229,13 +252,6 @@ config BACKLIGHT_HP700 If you have an HP Jornada 700 series, say Y to include backlight control driver. -config BACKLIGHT_PROGEAR - tristate "Frontpath ProGear Backlight Driver" - depends on PCI && X86 - help - If you have a Frontpath ProGear say Y to enable the - backlight driver. - config BACKLIGHT_CARILLO_RANCH tristate "Intel Carillo Ranch Backlight Driver" depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 @@ -245,7 +261,7 @@ config BACKLIGHT_CARILLO_RANCH config BACKLIGHT_PWM tristate "Generic PWM based Backlight Driver" - depends on HAVE_PWM + depends on PWM help If you have a LCD backlight adjustable by PWM, say Y to enable this driver. @@ -352,12 +368,34 @@ config BACKLIGHT_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the backlight driver. +config BACKLIGHT_LM3630A + tristate "Backlight Driver for LM3630A" + depends on BACKLIGHT_CLASS_DEVICE && I2C && PWM + select REGMAP_I2C + help + This supports TI LM3630A Backlight Driver + +config BACKLIGHT_LM3639 + tristate "Backlight Driver for LM3639" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select REGMAP_I2C + select NEW_LEDS + select LEDS_CLASS + help + This supports TI LM3639 Backlight + 1.5A Flash LED Driver + config BACKLIGHT_LP855X tristate "Backlight driver for TI LP855X" - depends on BACKLIGHT_CLASS_DEVICE && I2C + depends on BACKLIGHT_CLASS_DEVICE && I2C && PWM help - This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556 - backlight driver. + This supports TI LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and + LP8557 backlight driver. + +config BACKLIGHT_LP8788 + tristate "Backlight driver for TI LP8788 MFD" + depends on BACKLIGHT_CLASS_DEVICE && MFD_LP8788 && PWM + help + This supports TI LP8788 backlight driver. config BACKLIGHT_OT200 tristate "Backlight driver for ot200 visualisation device" @@ -373,6 +411,39 @@ 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. + +config BACKLIGHT_AS3711 + tristate "AS3711 Backlight" + depends on BACKLIGHT_CLASS_DEVICE && MFD_AS3711 + help + If you have an Austrian Microsystems AS3711 say Y to enable the + backlight driver. + +config BACKLIGHT_GPIO + tristate "Generic GPIO based Backlight Driver" + depends on GPIOLIB + help + If you have a LCD backlight adjustable by GPIO, say Y to enable + this driver. + +config BACKLIGHT_LV5207LP + tristate "Sanyo LV5207LP Backlight" + depends on I2C + help + If you have a Sanyo LV5207LP say Y to enable the backlight driver. + +config BACKLIGHT_BD6107 + tristate "Rohm BD6107 Backlight" + depends on I2C + help + If you have a Rohm BD6107 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 a2ac9cfbaf6..bb820024f34 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -1,45 +1,55 @@ # Backlight & LCD drivers -obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o -obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o -obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o -obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o -obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o -obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o -obj-$(CONFIG_LCD_ILI9320) += ili9320.o -obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o -obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o -obj-$(CONFIG_LCD_TDO24M) += tdo24m.o -obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o -obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o -obj-$(CONFIG_LCD_LD9040) += ld9040.o -obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o +obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o +obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o +obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o +obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o +obj-$(CONFIG_LCD_HX8357) += hx8357.o +obj-$(CONFIG_LCD_ILI922X) += ili922x.o +obj-$(CONFIG_LCD_ILI9320) += ili9320.o +obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o +obj-$(CONFIG_LCD_LD9040) += ld9040.o +obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o +obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o +obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o +obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o +obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o +obj-$(CONFIG_LCD_TDO24M) += tdo24m.o +obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o +obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o -obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o -obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o -obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o -obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o -obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o -obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o -obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o -obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o -obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o -obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o -obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o -obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o -obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o -obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o -obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o -obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o -obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o -obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o -obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o -obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o -obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o -obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o -obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o -obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o -obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o +obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o +obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o +obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o +obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o +obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o +obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o +obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o +obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o +obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o +obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o +obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o +obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o +obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o +obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o +obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o +obj-$(CONFIG_BACKLIGHT_GPIO) += gpio_backlight.o +obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o +obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o +obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o +obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o +obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o +obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o +obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o +obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o +obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o +obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o +obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o +obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o +obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_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_PWM) += pwm_bl.o +obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o +obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o +obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o +obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 7ff752288b9..ec5350f2c28 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -74,7 +74,7 @@ static int aat2870_bl_get_brightness(struct backlight_device *bd) static int aat2870_bl_update_status(struct backlight_device *bd) { - struct aat2870_bl_driver_data *aat2870_bl = dev_get_drvdata(&bd->dev); + struct aat2870_bl_driver_data *aat2870_bl = bl_get_data(bd); struct aat2870_data *aat2870 = dev_get_drvdata(aat2870_bl->pdev->dev.parent); int brightness = bd->props.brightness; @@ -127,7 +127,7 @@ static const struct backlight_ops aat2870_bl_ops = { static int aat2870_bl_probe(struct platform_device *pdev) { - struct aat2870_bl_platform_data *pdata = pdev->dev.platform_data; + struct aat2870_bl_platform_data *pdata = dev_get_platdata(&pdev->dev); struct aat2870_bl_driver_data *aat2870_bl; struct backlight_device *bd; struct backlight_properties props; @@ -149,8 +149,6 @@ static int aat2870_bl_probe(struct platform_device *pdev) sizeof(struct aat2870_bl_driver_data), GFP_KERNEL); if (!aat2870_bl) { - dev_err(&pdev->dev, - "Failed to allocate memory for aat2870 backlight\n"); ret = -ENOMEM; goto out; } @@ -158,8 +156,9 @@ static int aat2870_bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; - bd = backlight_device_register("aat2870-backlight", &pdev->dev, - aat2870_bl, &aat2870_bl_ops, &props); + bd = devm_backlight_device_register(&pdev->dev, "aat2870-backlight", + &pdev->dev, aat2870_bl, &aat2870_bl_ops, + &props); if (IS_ERR(bd)) { dev_err(&pdev->dev, "Failed allocate memory for backlight device\n"); @@ -194,13 +193,11 @@ static int aat2870_bl_probe(struct platform_device *pdev) ret = aat2870_bl_update_status(bd); if (ret < 0) { dev_err(&pdev->dev, "Failed to initialize\n"); - goto out_bl_dev_unregister; + return ret; } return 0; -out_bl_dev_unregister: - backlight_device_unregister(bd); out: return ret; } @@ -214,8 +211,6 @@ static int aat2870_bl_remove(struct platform_device *pdev) bd->props.brightness = 0; backlight_update_status(bd); - backlight_device_unregister(bd); - return 0; } diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index df5db99af23..f37097a261a 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -143,13 +143,16 @@ static int adp5520_bl_setup(struct backlight_device *bl) static ssize_t adp5520_show(struct device *dev, char *buf, int reg) { struct adp5520_bl *data = dev_get_drvdata(dev); - int error; + int ret; uint8_t reg_val; mutex_lock(&data->lock); - error = adp5520_read(data->master, reg, ®_val); + ret = adp5520_read(data->master, reg, ®_val); mutex_unlock(&data->lock); + if (ret < 0) + return ret; + return sprintf(buf, "%u\n", reg_val); } @@ -282,7 +285,7 @@ static const struct attribute_group adp5520_bl_attr_group = { .attrs = adp5520_bl_attributes, }; -static int __devinit adp5520_bl_probe(struct platform_device *pdev) +static int adp5520_bl_probe(struct platform_device *pdev) { struct backlight_properties props; struct backlight_device *bl; @@ -294,7 +297,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) return -ENOMEM; data->master = pdev->dev.parent; - data->pdata = pdev->dev.platform_data; + data->pdata = dev_get_platdata(&pdev->dev); if (data->pdata == NULL) { dev_err(&pdev->dev, "missing platform data\n"); @@ -309,8 +312,9 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = ADP5020_MAX_BRIGHTNESS; - bl = backlight_device_register(pdev->name, data->master, data, - &adp5520_bl_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, + data->master, data, &adp5520_bl_ops, + &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -323,7 +327,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to register sysfs\n"); - backlight_device_unregister(bl); + return ret; } platform_set_drvdata(pdev, bl); @@ -333,7 +337,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) return ret; } -static int __devexit adp5520_bl_remove(struct platform_device *pdev) +static int adp5520_bl_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); struct adp5520_bl *data = bl_get_data(bl); @@ -344,40 +348,37 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev) sysfs_remove_group(&bl->dev.kobj, &adp5520_bl_attr_group); - backlight_device_unregister(bl); - return 0; } -#ifdef CONFIG_PM -static int adp5520_bl_suspend(struct platform_device *pdev, - pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int adp5520_bl_suspend(struct device *dev) { - struct backlight_device *bl = platform_get_drvdata(pdev); + struct backlight_device *bl = dev_get_drvdata(dev); + return adp5520_bl_set(bl, 0); } -static int adp5520_bl_resume(struct platform_device *pdev) +static int adp5520_bl_resume(struct device *dev) { - struct backlight_device *bl = platform_get_drvdata(pdev); + struct backlight_device *bl = dev_get_drvdata(dev); backlight_update_status(bl); return 0; } -#else -#define adp5520_bl_suspend NULL -#define adp5520_bl_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adp5520_bl_pm_ops, adp5520_bl_suspend, + adp5520_bl_resume); + static struct platform_driver adp5520_bl_driver = { .driver = { .name = "adp5520-backlight", .owner = THIS_MODULE, + .pm = &adp5520_bl_pm_ops, }, .probe = adp5520_bl_probe, - .remove = __devexit_p(adp5520_bl_remove), - .suspend = adp5520_bl_suspend, - .resume = adp5520_bl_resume, + .remove = adp5520_bl_remove, }; module_platform_driver(adp5520_bl_driver); diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 77d1fdba597..be8d83deca7 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -213,10 +213,10 @@ static int adp8860_led_setup(struct adp8860_led *led) return ret; } -static int __devinit adp8860_led_probe(struct i2c_client *client) +static int adp8860_led_probe(struct i2c_client *client) { struct adp8860_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8860_bl *data = i2c_get_clientdata(client); struct adp8860_led *led, *led_dat; struct led_info *cur_led; @@ -224,10 +224,8 @@ static int __devinit adp8860_led_probe(struct i2c_client *client) led = devm_kzalloc(&client->dev, sizeof(*led) * pdata->num_leds, GFP_KERNEL); - if (led == NULL) { - dev_err(&client->dev, "failed to alloc memory\n"); + if (led == NULL) return -ENOMEM; - } ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law); ret = adp8860_write(client, ADP8860_ISCT1, @@ -249,12 +247,14 @@ static int __devinit adp8860_led_probe(struct i2c_client *client) if (led_dat->id > 7 || led_dat->id < 1) { dev_err(&client->dev, "Invalid LED ID %d\n", led_dat->id); + ret = -EINVAL; goto err; } if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { dev_err(&client->dev, "LED %d used by Backlight\n", led_dat->id); + ret = -EBUSY; goto err; } @@ -295,10 +295,10 @@ static int __devinit adp8860_led_probe(struct i2c_client *client) return ret; } -static int __devexit adp8860_led_remove(struct i2c_client *client) +static int adp8860_led_remove(struct i2c_client *client) { struct adp8860_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8860_bl *data = i2c_get_clientdata(client); int i; @@ -310,12 +310,12 @@ static int __devexit adp8860_led_remove(struct i2c_client *client) return 0; } #else -static int __devinit adp8860_led_probe(struct i2c_client *client) +static int adp8860_led_probe(struct i2c_client *client) { return 0; } -static int __devexit adp8860_led_remove(struct i2c_client *client) +static int adp8860_led_remove(struct i2c_client *client) { return 0; } @@ -650,13 +650,13 @@ static const struct attribute_group adp8860_bl_attr_group = { .attrs = adp8860_bl_attributes, }; -static int __devinit adp8860_probe(struct i2c_client *client, +static int adp8860_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct backlight_device *bl; struct adp8860_bl *data; struct adp8860_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct backlight_properties props; uint8_t reg_val; int ret; @@ -709,8 +709,9 @@ static int __devinit adp8860_probe(struct i2c_client *client, mutex_init(&data->lock); - bl = backlight_device_register(dev_driver_string(&client->dev), - &client->dev, data, &adp8860_bl_ops, &props); + bl = devm_backlight_device_register(&client->dev, + dev_driver_string(&client->dev), + &client->dev, data, &adp8860_bl_ops, &props); if (IS_ERR(bl)) { dev_err(&client->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -726,7 +727,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "failed to register sysfs\n"); - goto out1; + return ret; } ret = adp8860_bl_setup(bl); @@ -749,13 +750,11 @@ out: if (data->en_ambl_sens) sysfs_remove_group(&data->bl->dev.kobj, &adp8860_bl_attr_group); -out1: - backlight_device_unregister(bl); return ret; } -static int __devexit adp8860_remove(struct i2c_client *client) +static int adp8860_remove(struct i2c_client *client) { struct adp8860_bl *data = i2c_get_clientdata(client); @@ -768,30 +767,32 @@ static int __devexit adp8860_remove(struct i2c_client *client) sysfs_remove_group(&data->bl->dev.kobj, &adp8860_bl_attr_group); - backlight_device_unregister(data->bl); - return 0; } -#ifdef CONFIG_PM -static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int adp8860_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); return 0; } -static int adp8860_i2c_resume(struct i2c_client *client) +static int adp8860_i2c_resume(struct device *dev) { - adp8860_set_bits(client, ADP8860_MDCR, NSTBY); + struct i2c_client *client = to_i2c_client(dev); + + adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN); return 0; } -#else -#define adp8860_i2c_suspend NULL -#define adp8860_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adp8860_i2c_pm_ops, adp8860_i2c_suspend, + adp8860_i2c_resume); + static const struct i2c_device_id adp8860_id[] = { { "adp8860", adp8860 }, { "adp8861", adp8861 }, @@ -802,12 +803,11 @@ MODULE_DEVICE_TABLE(i2c, adp8860_id); static struct i2c_driver adp8860_driver = { .driver = { - .name = KBUILD_MODNAME, + .name = KBUILD_MODNAME, + .pm = &adp8860_i2c_pm_ops, }, .probe = adp8860_probe, - .remove = __devexit_p(adp8860_remove), - .suspend = adp8860_i2c_suspend, - .resume = adp8860_i2c_resume, + .remove = adp8860_remove, .id_table = adp8860_id, }; diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index edf7f91c8e6..251af4d38d8 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -235,10 +235,10 @@ static int adp8870_led_setup(struct adp8870_led *led) return ret; } -static int __devinit adp8870_led_probe(struct i2c_client *client) +static int adp8870_led_probe(struct i2c_client *client) { struct adp8870_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8870_bl *data = i2c_get_clientdata(client); struct adp8870_led *led, *led_dat; struct led_info *cur_led; @@ -246,10 +246,8 @@ static int __devinit adp8870_led_probe(struct i2c_client *client) led = devm_kzalloc(&client->dev, pdata->num_leds * sizeof(*led), GFP_KERNEL); - if (led == NULL) { - dev_err(&client->dev, "failed to alloc memory\n"); + if (led == NULL) return -ENOMEM; - } ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law); if (ret) @@ -274,12 +272,14 @@ static int __devinit adp8870_led_probe(struct i2c_client *client) if (led_dat->id > 7 || led_dat->id < 1) { dev_err(&client->dev, "Invalid LED ID %d\n", led_dat->id); + ret = -EINVAL; goto err; } if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { dev_err(&client->dev, "LED %d used by Backlight\n", led_dat->id); + ret = -EBUSY; goto err; } @@ -320,10 +320,10 @@ static int __devinit adp8870_led_probe(struct i2c_client *client) return ret; } -static int __devexit adp8870_led_remove(struct i2c_client *client) +static int adp8870_led_remove(struct i2c_client *client) { struct adp8870_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8870_bl *data = i2c_get_clientdata(client); int i; @@ -335,12 +335,12 @@ static int __devexit adp8870_led_remove(struct i2c_client *client) return 0; } #else -static int __devinit adp8870_led_probe(struct i2c_client *client) +static int adp8870_led_probe(struct i2c_client *client) { return 0; } -static int __devexit adp8870_led_remove(struct i2c_client *client) +static int adp8870_led_remove(struct i2c_client *client) { return 0; } @@ -839,14 +839,14 @@ static const struct attribute_group adp8870_bl_attr_group = { .attrs = adp8870_bl_attributes, }; -static int __devinit adp8870_probe(struct i2c_client *client, +static int adp8870_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct backlight_properties props; struct backlight_device *bl; struct adp8870_bl *data; struct adp8870_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); uint8_t reg_val; int ret; @@ -886,8 +886,9 @@ static int __devinit adp8870_probe(struct i2c_client *client, memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = props.brightness = ADP8870_MAX_BRIGHTNESS; - bl = backlight_device_register(dev_driver_string(&client->dev), - &client->dev, data, &adp8870_bl_ops, &props); + bl = devm_backlight_device_register(&client->dev, + dev_driver_string(&client->dev), + &client->dev, data, &adp8870_bl_ops, &props); if (IS_ERR(bl)) { dev_err(&client->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -895,13 +896,13 @@ static int __devinit adp8870_probe(struct i2c_client *client, data->bl = bl; - if (pdata->en_ambl_sens) + if (pdata->en_ambl_sens) { ret = sysfs_create_group(&bl->dev.kobj, &adp8870_bl_attr_group); - - if (ret) { - dev_err(&client->dev, "failed to register sysfs\n"); - goto out1; + if (ret) { + dev_err(&client->dev, "failed to register sysfs\n"); + return ret; + } } ret = adp8870_bl_setup(bl); @@ -923,13 +924,11 @@ out: if (data->pdata->en_ambl_sens) sysfs_remove_group(&data->bl->dev.kobj, &adp8870_bl_attr_group); -out1: - backlight_device_unregister(bl); return ret; } -static int __devexit adp8870_remove(struct i2c_client *client) +static int adp8870_remove(struct i2c_client *client) { struct adp8870_bl *data = i2c_get_clientdata(client); @@ -942,30 +941,32 @@ static int __devexit adp8870_remove(struct i2c_client *client) sysfs_remove_group(&data->bl->dev.kobj, &adp8870_bl_attr_group); - backlight_device_unregister(data->bl); - return 0; } -#ifdef CONFIG_PM -static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int adp8870_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + adp8870_clr_bits(client, ADP8870_MDCR, NSTBY); return 0; } -static int adp8870_i2c_resume(struct i2c_client *client) +static int adp8870_i2c_resume(struct device *dev) { - adp8870_set_bits(client, ADP8870_MDCR, NSTBY); + struct i2c_client *client = to_i2c_client(dev); + + adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN); return 0; } -#else -#define adp8870_i2c_suspend NULL -#define adp8870_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adp8870_i2c_pm_ops, adp8870_i2c_suspend, + adp8870_i2c_resume); + static const struct i2c_device_id adp8870_id[] = { { "adp8870", 0 }, { } @@ -974,12 +975,11 @@ MODULE_DEVICE_TABLE(i2c, adp8870_id); static struct i2c_driver adp8870_driver = { .driver = { - .name = KBUILD_MODNAME, + .name = KBUILD_MODNAME, + .pm = &adp8870_i2c_pm_ops, }, .probe = adp8870_probe, - .remove = __devexit_p(adp8870_remove), - .suspend = adp8870_i2c_suspend, - .resume = adp8870_i2c_resume, + .remove = adp8870_remove, .id_table = adp8870_id, }; diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 3729238e709..d8952c4aa68 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -10,25 +10,16 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <linux/wait.h> -#include <linux/module.h> -#include <linux/fb.h> +#include <linux/backlight.h> #include <linux/delay.h> +#include <linux/fb.h> #include <linux/gpio.h> -#include <linux/spi/spi.h> #include <linux/lcd.h> -#include <linux/backlight.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/wait.h> #define SLEEPMSEC 0x1000 #define ENDDEF 0x2000 @@ -210,8 +201,9 @@ static int ams369fg06_panel_send_sequence(struct ams369fg06 *lcd, ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]); if (ret) break; - } else - mdelay(wbuf[i+1]); + } else { + msleep(wbuf[i+1]); + } i += 2; } @@ -313,41 +305,29 @@ static int ams369fg06_ldi_disable(struct ams369fg06 *lcd) static int ams369fg06_power_is_on(int power) { - return ((power) <= FB_BLANK_NORMAL); + return power <= FB_BLANK_NORMAL; } static int ams369fg06_power_on(struct ams369fg06 *lcd) { int ret = 0; - struct lcd_platform_data *pd = NULL; - struct backlight_device *bd = NULL; + struct lcd_platform_data *pd; + struct backlight_device *bd; pd = lcd->lcd_pd; - if (!pd) { - dev_err(lcd->dev, "platform data is NULL.\n"); - return -EFAULT; - } - bd = lcd->bd; - if (!bd) { - dev_err(lcd->dev, "backlight device is NULL.\n"); - return -EFAULT; - } - if (!pd->power_on) { - dev_err(lcd->dev, "power_on is NULL.\n"); - return -EFAULT; - } else { + if (pd->power_on) { pd->power_on(lcd->ld, 1); - mdelay(pd->power_on_delay); + msleep(pd->power_on_delay); } if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); - return -EFAULT; + return -EINVAL; } else { pd->reset(lcd->ld); - mdelay(pd->reset_delay); + msleep(pd->reset_delay); } ret = ams369fg06_ldi_init(lcd); @@ -374,14 +354,10 @@ static int ams369fg06_power_on(struct ams369fg06 *lcd) static int ams369fg06_power_off(struct ams369fg06 *lcd) { - int ret = 0; - struct lcd_platform_data *pd = NULL; + int ret; + struct lcd_platform_data *pd; pd = lcd->lcd_pd; - if (!pd) { - dev_err(lcd->dev, "platform data is NULL\n"); - return -EFAULT; - } ret = ams369fg06_ldi_disable(lcd); if (ret) { @@ -389,12 +365,9 @@ static int ams369fg06_power_off(struct ams369fg06 *lcd) return -EIO; } - mdelay(pd->power_off_delay); + msleep(pd->power_off_delay); - if (!pd->power_on) { - dev_err(lcd->dev, "power_on is NULL.\n"); - return -EFAULT; - } else + if (pd->power_on) pd->power_on(lcd->ld, 0); return 0; @@ -446,7 +419,7 @@ static int ams369fg06_set_brightness(struct backlight_device *bd) { int ret = 0; int brightness = bd->props.brightness; - struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev); + struct ams369fg06 *lcd = bl_get_data(bd); if (brightness < MIN_BRIGHTNESS || brightness > bd->props.max_brightness) { @@ -474,7 +447,7 @@ static const struct backlight_ops ams369fg06_backlight_ops = { .update_status = ams369fg06_set_brightness, }; -static int __devinit ams369fg06_probe(struct spi_device *spi) +static int ams369fg06_probe(struct spi_device *spi) { int ret = 0; struct ams369fg06 *lcd = NULL; @@ -498,14 +471,14 @@ static int __devinit ams369fg06_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL\n"); - return -EFAULT; + return -EINVAL; } - ld = lcd_device_register("ams369fg06", &spi->dev, lcd, - &ams369fg06_lcd_ops); + ld = devm_lcd_device_register(&spi->dev, "ams369fg06", &spi->dev, lcd, + &ams369fg06_lcd_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -515,12 +488,11 @@ static int __devinit ams369fg06_probe(struct spi_device *spi) props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bd = backlight_device_register("ams369fg06-bl", &spi->dev, lcd, - &ams369fg06_backlight_ops, &props); - if (IS_ERR(bd)) { - ret = PTR_ERR(bd); - goto out_lcd_unregister; - } + bd = devm_backlight_device_register(&spi->dev, "ams369fg06-bl", + &spi->dev, lcd, + &ams369fg06_backlight_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); bd->props.brightness = DEFAULT_BRIGHTNESS; lcd->bd = bd; @@ -534,79 +506,55 @@ static int __devinit ams369fg06_probe(struct spi_device *spi) lcd->power = FB_BLANK_POWERDOWN; ams369fg06_power(lcd, FB_BLANK_UNBLANK); - } else + } else { lcd->power = FB_BLANK_UNBLANK; + } - dev_set_drvdata(&spi->dev, lcd); + spi_set_drvdata(spi, lcd); dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n"); return 0; - -out_lcd_unregister: - lcd_device_unregister(ld); - return ret; } -static int __devexit ams369fg06_remove(struct spi_device *spi) +static int ams369fg06_remove(struct spi_device *spi) { - struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); + struct ams369fg06 *lcd = spi_get_drvdata(spi); ams369fg06_power(lcd, FB_BLANK_POWERDOWN); - backlight_device_unregister(lcd->bd); - lcd_device_unregister(lcd->ld); - return 0; } -#if defined(CONFIG_PM) -static unsigned int before_power; - -static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int ams369fg06_suspend(struct device *dev) { - int ret = 0; - struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); - - dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + struct ams369fg06 *lcd = dev_get_drvdata(dev); - before_power = lcd->power; + dev_dbg(dev, "lcd->power = %d\n", lcd->power); /* * when lcd panel is suspend, lcd panel becomes off * regardless of status. */ - ret = ams369fg06_power(lcd, FB_BLANK_POWERDOWN); - - return ret; + return ams369fg06_power(lcd, FB_BLANK_POWERDOWN); } -static int ams369fg06_resume(struct spi_device *spi) +static int ams369fg06_resume(struct device *dev) { - int ret = 0; - struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); - - /* - * after suspended, if lcd panel status is FB_BLANK_UNBLANK - * (at that time, before_power is FB_BLANK_UNBLANK) then - * it changes that status to FB_BLANK_POWERDOWN to get lcd on. - */ - if (before_power == FB_BLANK_UNBLANK) - lcd->power = FB_BLANK_POWERDOWN; - - dev_dbg(&spi->dev, "before_power = %d\n", before_power); + struct ams369fg06 *lcd = dev_get_drvdata(dev); - ret = ams369fg06_power(lcd, before_power); + lcd->power = FB_BLANK_POWERDOWN; - return ret; + return ams369fg06_power(lcd, FB_BLANK_UNBLANK); } -#else -#define ams369fg06_suspend NULL -#define ams369fg06_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ams369fg06_pm_ops, ams369fg06_suspend, + ams369fg06_resume); + static void ams369fg06_shutdown(struct spi_device *spi) { - struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); + struct ams369fg06 *lcd = spi_get_drvdata(spi); ams369fg06_power(lcd, FB_BLANK_POWERDOWN); } @@ -615,12 +563,11 @@ static struct spi_driver ams369fg06_driver = { .driver = { .name = "ams369fg06", .owner = THIS_MODULE, + .pm = &ams369fg06_pm_ops, }, .probe = ams369fg06_probe, - .remove = __devexit_p(ams369fg06_remove), + .remove = ams369fg06_remove, .shutdown = ams369fg06_shutdown, - .suspend = ams369fg06_suspend, - .resume = ams369fg06_resume, }; module_spi_driver(ams369fg06_driver); diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c index 9dc73ac3709..d8432967668 100644 --- a/drivers/video/backlight/apple_bl.c +++ b/drivers/video/backlight/apple_bl.c @@ -137,7 +137,7 @@ static const struct hw_data nvidia_chipset_data = { .set_brightness = nvidia_chipset_set_brightness, }; -static int __devinit apple_bl_add(struct acpi_device *dev) +static int apple_bl_add(struct acpi_device *dev) { struct backlight_properties props; struct pci_dev *host; @@ -196,7 +196,7 @@ static int __devinit apple_bl_add(struct acpi_device *dev) return 0; } -static int __devexit apple_bl_remove(struct acpi_device *dev, int type) +static int apple_bl_remove(struct acpi_device *dev) { backlight_device_unregister(apple_backlight_device); diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c new file mode 100644 index 00000000000..bb1fc45b754 --- /dev/null +++ b/drivers/video/backlight/as3711_bl.c @@ -0,0 +1,480 @@ +/* + * AS3711 PMIC backlight driver, using DCDC Step Up Converters + * + * Copyright (C) 2012 Renesas Electronics Corporation + * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License as + * published by the Free Software Foundation + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/kernel.h> +#include <linux/mfd/as3711.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +enum as3711_bl_type { + AS3711_BL_SU1, + AS3711_BL_SU2, +}; + +struct as3711_bl_data { + bool powered; + const char *fb_name; + struct device *fb_dev; + enum as3711_bl_type type; + int brightness; + struct backlight_device *bl; +}; + +struct as3711_bl_supply { + struct as3711_bl_data su1; + struct as3711_bl_data su2; + const struct as3711_bl_pdata *pdata; + struct as3711 *as3711; +}; + +static struct as3711_bl_supply *to_supply(struct as3711_bl_data *su) +{ + switch (su->type) { + case AS3711_BL_SU1: + return container_of(su, struct as3711_bl_supply, su1); + case AS3711_BL_SU2: + return container_of(su, struct as3711_bl_supply, su2); + } + return NULL; +} + +static int as3711_set_brightness_auto_i(struct as3711_bl_data *data, + unsigned int brightness) +{ + struct as3711_bl_supply *supply = to_supply(data); + struct as3711 *as3711 = supply->as3711; + const struct as3711_bl_pdata *pdata = supply->pdata; + int ret = 0; + + /* Only all equal current values are supported */ + if (pdata->su2_auto_curr1) + ret = regmap_write(as3711->regmap, AS3711_CURR1_VALUE, + brightness); + if (!ret && pdata->su2_auto_curr2) + ret = regmap_write(as3711->regmap, AS3711_CURR2_VALUE, + brightness); + if (!ret && pdata->su2_auto_curr3) + ret = regmap_write(as3711->regmap, AS3711_CURR3_VALUE, + brightness); + + return ret; +} + +static int as3711_set_brightness_v(struct as3711 *as3711, + unsigned int brightness, + unsigned int reg) +{ + if (brightness > 31) + return -EINVAL; + + return regmap_update_bits(as3711->regmap, reg, 0xf0, + brightness << 4); +} + +static int as3711_bl_su2_reset(struct as3711_bl_supply *supply) +{ + struct as3711 *as3711 = supply->as3711; + int ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_5, + 3, supply->pdata->su2_fbprot); + if (!ret) + ret = regmap_update_bits(as3711->regmap, + AS3711_STEPUP_CONTROL_2, 1, 0); + if (!ret) + ret = regmap_update_bits(as3711->regmap, + AS3711_STEPUP_CONTROL_2, 1, 1); + return ret; +} + +/* + * Someone with less fragile or less expensive hardware could try to simplify + * the brightness adjustment procedure. + */ +static int as3711_bl_update_status(struct backlight_device *bl) +{ + struct as3711_bl_data *data = bl_get_data(bl); + struct as3711_bl_supply *supply = to_supply(data); + struct as3711 *as3711 = supply->as3711; + int brightness = bl->props.brightness; + int ret = 0; + + dev_dbg(&bl->dev, "%s(): brightness %u, pwr %x, blank %x, state %x\n", + __func__, bl->props.brightness, bl->props.power, + bl->props.fb_blank, bl->props.state); + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + if (data->type == AS3711_BL_SU1) { + ret = as3711_set_brightness_v(as3711, brightness, + AS3711_STEPUP_CONTROL_1); + } else { + const struct as3711_bl_pdata *pdata = supply->pdata; + + switch (pdata->su2_feedback) { + case AS3711_SU2_VOLTAGE: + ret = as3711_set_brightness_v(as3711, brightness, + AS3711_STEPUP_CONTROL_2); + break; + case AS3711_SU2_CURR_AUTO: + ret = as3711_set_brightness_auto_i(data, brightness / 4); + if (ret < 0) + return ret; + if (brightness) { + ret = as3711_bl_su2_reset(supply); + if (ret < 0) + return ret; + udelay(500); + ret = as3711_set_brightness_auto_i(data, brightness); + } else { + ret = regmap_update_bits(as3711->regmap, + AS3711_STEPUP_CONTROL_2, 1, 0); + } + break; + /* Manual one current feedback pin below */ + case AS3711_SU2_CURR1: + ret = regmap_write(as3711->regmap, AS3711_CURR1_VALUE, + brightness); + break; + case AS3711_SU2_CURR2: + ret = regmap_write(as3711->regmap, AS3711_CURR2_VALUE, + brightness); + break; + case AS3711_SU2_CURR3: + ret = regmap_write(as3711->regmap, AS3711_CURR3_VALUE, + brightness); + break; + default: + ret = -EINVAL; + } + } + if (!ret) + data->brightness = brightness; + + return ret; +} + +static int as3711_bl_get_brightness(struct backlight_device *bl) +{ + struct as3711_bl_data *data = bl_get_data(bl); + + return data->brightness; +} + +static const struct backlight_ops as3711_bl_ops = { + .update_status = as3711_bl_update_status, + .get_brightness = as3711_bl_get_brightness, +}; + +static int as3711_bl_init_su2(struct as3711_bl_supply *supply) +{ + struct as3711 *as3711 = supply->as3711; + const struct as3711_bl_pdata *pdata = supply->pdata; + u8 ctl = 0; + int ret; + + dev_dbg(as3711->dev, "%s(): use %u\n", __func__, pdata->su2_feedback); + + /* Turn SU2 off */ + ret = regmap_write(as3711->regmap, AS3711_STEPUP_CONTROL_2, 0); + if (ret < 0) + return ret; + + switch (pdata->su2_feedback) { + case AS3711_SU2_VOLTAGE: + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 0); + break; + case AS3711_SU2_CURR1: + ctl = 1; + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 1); + break; + case AS3711_SU2_CURR2: + ctl = 4; + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 2); + break; + case AS3711_SU2_CURR3: + ctl = 0x10; + ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 3); + break; + case AS3711_SU2_CURR_AUTO: + if (pdata->su2_auto_curr1) + ctl = 2; + if (pdata->su2_auto_curr2) + ctl |= 8; + if (pdata->su2_auto_curr3) + ctl |= 0x20; + ret = 0; + break; + default: + return -EINVAL; + } + + if (!ret) + ret = regmap_write(as3711->regmap, AS3711_CURR_CONTROL, ctl); + + return ret; +} + +static int as3711_bl_register(struct platform_device *pdev, + unsigned int max_brightness, struct as3711_bl_data *su) +{ + struct backlight_properties props = {.type = BACKLIGHT_RAW,}; + struct backlight_device *bl; + + /* max tuning I = 31uA for voltage- and 38250uA for current-feedback */ + props.max_brightness = max_brightness; + + bl = devm_backlight_device_register(&pdev->dev, + su->type == AS3711_BL_SU1 ? + "as3711-su1" : "as3711-su2", + &pdev->dev, su, + &as3711_bl_ops, &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } + + bl->props.brightness = props.max_brightness; + + backlight_update_status(bl); + + su->bl = bl; + + return 0; +} + +static int as3711_backlight_parse_dt(struct device *dev) +{ + struct as3711_bl_pdata *pdata = dev_get_platdata(dev); + struct device_node *bl = + of_find_node_by_name(dev->parent->of_node, "backlight"), *fb; + int ret; + + if (!bl) { + dev_dbg(dev, "backlight node not found\n"); + return -ENODEV; + } + + fb = of_parse_phandle(bl, "su1-dev", 0); + if (fb) { + pdata->su1_fb = fb->full_name; + + ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA); + if (pdata->su1_max_uA <= 0) + ret = -EINVAL; + if (ret < 0) + return ret; + } + + fb = of_parse_phandle(bl, "su2-dev", 0); + if (fb) { + int count = 0; + + pdata->su2_fb = fb->full_name; + + ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA); + if (pdata->su2_max_uA <= 0) + ret = -EINVAL; + if (ret < 0) + return ret; + + if (of_find_property(bl, "su2-feedback-voltage", NULL)) { + pdata->su2_feedback = AS3711_SU2_VOLTAGE; + count++; + } + if (of_find_property(bl, "su2-feedback-curr1", NULL)) { + pdata->su2_feedback = AS3711_SU2_CURR1; + count++; + } + if (of_find_property(bl, "su2-feedback-curr2", NULL)) { + pdata->su2_feedback = AS3711_SU2_CURR2; + count++; + } + if (of_find_property(bl, "su2-feedback-curr3", NULL)) { + pdata->su2_feedback = AS3711_SU2_CURR3; + count++; + } + if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) { + pdata->su2_feedback = AS3711_SU2_CURR_AUTO; + count++; + } + if (count != 1) + return -EINVAL; + + count = 0; + if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { + pdata->su2_fbprot = AS3711_SU2_LX_SD4; + count++; + } + if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) { + pdata->su2_fbprot = AS3711_SU2_GPIO2; + count++; + } + if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) { + pdata->su2_fbprot = AS3711_SU2_GPIO3; + count++; + } + if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) { + pdata->su2_fbprot = AS3711_SU2_GPIO4; + count++; + } + if (count != 1) + return -EINVAL; + + count = 0; + if (of_find_property(bl, "su2-auto-curr1", NULL)) { + pdata->su2_auto_curr1 = true; + count++; + } + if (of_find_property(bl, "su2-auto-curr2", NULL)) { + pdata->su2_auto_curr2 = true; + count++; + } + if (of_find_property(bl, "su2-auto-curr3", NULL)) { + pdata->su2_auto_curr3 = true; + count++; + } + + /* + * At least one su2-auto-curr* must be specified iff + * AS3711_SU2_CURR_AUTO is used + */ + if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) + return -EINVAL; + } + + return 0; +} + +static int as3711_backlight_probe(struct platform_device *pdev) +{ + struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev); + struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); + struct as3711_bl_supply *supply; + struct as3711_bl_data *su; + unsigned int max_brightness; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "No platform data, exiting...\n"); + return -ENODEV; + } + + if (pdev->dev.parent->of_node) { + ret = as3711_backlight_parse_dt(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "DT parsing failed: %d\n", ret); + return ret; + } + } + + if (!pdata->su1_fb && !pdata->su2_fb) { + dev_err(&pdev->dev, "No framebuffer specified\n"); + return -EINVAL; + } + + /* + * Due to possible hardware damage I chose to block all modes, + * unsupported on my hardware. Anyone, wishing to use any of those modes + * will have to first review the code, then activate and test it. + */ + if (pdata->su1_fb || + pdata->su2_fbprot != AS3711_SU2_GPIO4 || + pdata->su2_feedback != AS3711_SU2_CURR_AUTO) { + dev_warn(&pdev->dev, + "Attention! An untested mode has been chosen!\n" + "Please, review the code, enable, test, and report success:-)\n"); + return -EINVAL; + } + + supply = devm_kzalloc(&pdev->dev, sizeof(*supply), GFP_KERNEL); + if (!supply) + return -ENOMEM; + + supply->as3711 = as3711; + supply->pdata = pdata; + + if (pdata->su1_fb) { + su = &supply->su1; + su->fb_name = pdata->su1_fb; + su->type = AS3711_BL_SU1; + + max_brightness = min(pdata->su1_max_uA, 31); + ret = as3711_bl_register(pdev, max_brightness, su); + if (ret < 0) + return ret; + } + + if (pdata->su2_fb) { + su = &supply->su2; + su->fb_name = pdata->su2_fb; + su->type = AS3711_BL_SU2; + + switch (pdata->su2_fbprot) { + case AS3711_SU2_GPIO2: + case AS3711_SU2_GPIO3: + case AS3711_SU2_GPIO4: + case AS3711_SU2_LX_SD4: + break; + default: + return -EINVAL; + } + + switch (pdata->su2_feedback) { + case AS3711_SU2_VOLTAGE: + max_brightness = min(pdata->su2_max_uA, 31); + break; + case AS3711_SU2_CURR1: + case AS3711_SU2_CURR2: + case AS3711_SU2_CURR3: + case AS3711_SU2_CURR_AUTO: + max_brightness = min(pdata->su2_max_uA / 150, 255); + break; + default: + return -EINVAL; + } + + ret = as3711_bl_init_su2(supply); + if (ret < 0) + return ret; + + ret = as3711_bl_register(pdev, max_brightness, su); + if (ret < 0) + return ret; + } + + platform_set_drvdata(pdev, supply); + + return 0; +} + +static struct platform_driver as3711_backlight_driver = { + .driver = { + .name = "as3711-backlight", + .owner = THIS_MODULE, + }, + .probe = as3711_backlight_probe, +}; + +module_platform_driver(as3711_backlight_driver); + +MODULE_DESCRIPTION("Backlight Driver for AS3711 PMICs"); +MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:as3711-backlight"); diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 0443a4f7185..261b1a4ec3d 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/fb.h> -#include <linux/clk.h> #include <linux/gpio.h> #include <linux/backlight.h> #include <linux/atmel_pwm.h> @@ -27,6 +26,14 @@ struct atmel_pwm_bl { int gpio_on; }; +static void atmel_pwm_bl_set_gpio_on(struct atmel_pwm_bl *pwmbl, int on) +{ + if (!gpio_is_valid(pwmbl->gpio_on)) + return; + + gpio_set_value(pwmbl->gpio_on, on ^ pwmbl->pdata->on_active_low); +} + static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) { struct atmel_pwm_bl *pwmbl = bl_get_data(bd); @@ -49,19 +56,13 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) pwm_duty = pwmbl->pdata->pwm_duty_min; if (!intensity) { - if (pwmbl->gpio_on != -1) { - gpio_set_value(pwmbl->gpio_on, - 0 ^ pwmbl->pdata->on_active_low); - } + atmel_pwm_bl_set_gpio_on(pwmbl, 0); pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); pwm_channel_disable(&pwmbl->pwmc); } else { pwm_channel_enable(&pwmbl->pwmc); pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); - if (pwmbl->gpio_on != -1) { - gpio_set_value(pwmbl->gpio_on, - 1 ^ pwmbl->pdata->on_active_low); - } + atmel_pwm_bl_set_gpio_on(pwmbl, 1); } return 0; @@ -70,17 +71,16 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) static int atmel_pwm_bl_get_intensity(struct backlight_device *bd) { struct atmel_pwm_bl *pwmbl = bl_get_data(bd); - u8 intensity; + u32 cdty; + u32 intensity; - if (pwmbl->pdata->pwm_active_low) { - intensity = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY) - - pwmbl->pdata->pwm_duty_min; - } else { - intensity = pwmbl->pdata->pwm_duty_max - - pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY); - } + cdty = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY); + if (pwmbl->pdata->pwm_active_low) + intensity = cdty - pwmbl->pdata->pwm_duty_min; + else + intensity = pwmbl->pdata->pwm_duty_max - cdty; - return intensity; + return intensity & 0xffff; } static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl) @@ -106,10 +106,9 @@ static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl) pwm_channel_writel(&pwmbl->pwmc, PWM_CPRD, pwmbl->pdata->pwm_compare_max); - dev_info(&pwmbl->pdev->dev, "Atmel PWM backlight driver " - "(%lu Hz)\n", pwmbl->pwmc.mck / - pwmbl->pdata->pwm_compare_max / - (1 << prescale)); + dev_info(&pwmbl->pdev->dev, "Atmel PWM backlight driver (%lu Hz)\n", + pwmbl->pwmc.mck / pwmbl->pdata->pwm_compare_max / + (1 << prescale)); return pwm_channel_enable(&pwmbl->pwmc); } @@ -125,56 +124,53 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) const struct atmel_pwm_bl_platform_data *pdata; struct backlight_device *bldev; struct atmel_pwm_bl *pwmbl; + unsigned long flags; int retval; - pwmbl = kzalloc(sizeof(struct atmel_pwm_bl), GFP_KERNEL); - if (!pwmbl) - return -ENOMEM; - - pwmbl->pdev = pdev; - - pdata = pdev->dev.platform_data; - if (!pdata) { - retval = -ENODEV; - goto err_free_mem; - } + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) + return -ENODEV; if (pdata->pwm_compare_max < pdata->pwm_duty_max || pdata->pwm_duty_min > pdata->pwm_duty_max || - pdata->pwm_frequency == 0) { - retval = -EINVAL; - goto err_free_mem; - } + pdata->pwm_frequency == 0) + return -EINVAL; + pwmbl = devm_kzalloc(&pdev->dev, sizeof(struct atmel_pwm_bl), + GFP_KERNEL); + if (!pwmbl) + return -ENOMEM; + + pwmbl->pdev = pdev; pwmbl->pdata = pdata; pwmbl->gpio_on = pdata->gpio_on; retval = pwm_channel_alloc(pdata->pwm_channel, &pwmbl->pwmc); if (retval) - goto err_free_mem; - - if (pwmbl->gpio_on != -1) { - retval = gpio_request(pwmbl->gpio_on, "gpio_atmel_pwm_bl"); - if (retval) { - pwmbl->gpio_on = -1; - goto err_free_pwm; - } + return retval; + if (gpio_is_valid(pwmbl->gpio_on)) { /* Turn display off by default. */ - retval = gpio_direction_output(pwmbl->gpio_on, - 0 ^ pdata->on_active_low); + if (pdata->on_active_low) + flags = GPIOF_OUT_INIT_HIGH; + else + flags = GPIOF_OUT_INIT_LOW; + + retval = devm_gpio_request_one(&pdev->dev, pwmbl->gpio_on, + flags, "gpio_atmel_pwm_bl"); if (retval) - goto err_free_gpio; + goto err_free_pwm; } memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min; - bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl, - &atmel_pwm_bl_ops, &props); + bldev = devm_backlight_device_register(&pdev->dev, "atmel-pwm-bl", + &pdev->dev, pwmbl, &atmel_pwm_bl_ops, + &props); if (IS_ERR(bldev)) { retval = PTR_ERR(bldev); - goto err_free_gpio; + goto err_free_pwm; } pwmbl->bldev = bldev; @@ -187,38 +183,25 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) retval = atmel_pwm_bl_init_pwm(pwmbl); if (retval) - goto err_free_bl_dev; + goto err_free_pwm; atmel_pwm_bl_set_intensity(bldev); return 0; -err_free_bl_dev: - platform_set_drvdata(pdev, NULL); - backlight_device_unregister(bldev); -err_free_gpio: - if (pwmbl->gpio_on != -1) - gpio_free(pwmbl->gpio_on); err_free_pwm: pwm_channel_free(&pwmbl->pwmc); -err_free_mem: - kfree(pwmbl); + return retval; } -static int __exit atmel_pwm_bl_remove(struct platform_device *pdev) +static int atmel_pwm_bl_remove(struct platform_device *pdev) { struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); - if (pwmbl->gpio_on != -1) { - gpio_set_value(pwmbl->gpio_on, 0); - gpio_free(pwmbl->gpio_on); - } + atmel_pwm_bl_set_gpio_on(pwmbl, 0); pwm_channel_disable(&pwmbl->pwmc); pwm_channel_free(&pwmbl->pwmc); - backlight_device_unregister(pwmbl->bldev); - platform_set_drvdata(pdev, NULL); - kfree(pwmbl); return 0; } @@ -228,21 +211,13 @@ static struct platform_driver atmel_pwm_bl_driver = { .name = "atmel-pwm-bl", }, /* REVISIT add suspend() and resume() */ - .remove = __exit_p(atmel_pwm_bl_remove), + .probe = atmel_pwm_bl_probe, + .remove = atmel_pwm_bl_remove, }; -static int __init atmel_pwm_bl_init(void) -{ - return platform_driver_probe(&atmel_pwm_bl_driver, atmel_pwm_bl_probe); -} -module_init(atmel_pwm_bl_init); - -static void __exit atmel_pwm_bl_exit(void) -{ - platform_driver_unregister(&atmel_pwm_bl_driver); -} -module_exit(atmel_pwm_bl_exit); +module_platform_driver(atmel_pwm_bl_driver); MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>"); MODULE_DESCRIPTION("Atmel PWM backlight driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:atmel-pwm-bl"); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 297db2fa91f..428089009cd 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -21,6 +21,10 @@ #include <asm/backlight.h> #endif +static struct list_head backlight_dev_list; +static struct mutex backlight_dev_list_mutex; +static struct blocking_notifier_head backlight_notifier; + static const char *const backlight_types[] = { [BACKLIGHT_RAW] = "raw", [BACKLIGHT_PLATFORM] = "platform", @@ -31,13 +35,15 @@ static const char *const backlight_types[] = { defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) /* This callback gets called when something important happens inside a * framebuffer driver. We're looking if that important event is blanking, - * and if it is, we're switching backlight power as well ... + * and if it is and necessary, we're switching backlight power as well ... */ static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct backlight_device *bd; struct fb_event *evdata = data; + int node = evdata->info->node; + int fb_blank = 0; /* If we aren't interested in this event, skip it immediately ... */ if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) @@ -48,12 +54,24 @@ static int fb_notifier_callback(struct notifier_block *self, if (bd->ops) if (!bd->ops->check_fb || bd->ops->check_fb(bd, evdata->info)) { - bd->props.fb_blank = *(int *)evdata->data; - if (bd->props.fb_blank == FB_BLANK_UNBLANK) - bd->props.state &= ~BL_CORE_FBBLANK; - else - bd->props.state |= BL_CORE_FBBLANK; - backlight_update_status(bd); + fb_blank = *(int *)evdata->data; + if (fb_blank == FB_BLANK_UNBLANK && + !bd->fb_bl_on[node]) { + bd->fb_bl_on[node] = true; + if (!bd->use_count++) { + bd->props.state &= ~BL_CORE_FBBLANK; + bd->props.fb_blank = FB_BLANK_UNBLANK; + backlight_update_status(bd); + } + } else if (fb_blank != FB_BLANK_UNBLANK && + bd->fb_bl_on[node]) { + bd->fb_bl_on[node] = false; + if (!(--bd->use_count)) { + bd->props.state |= BL_CORE_FBBLANK; + bd->props.fb_blank = fb_blank; + backlight_update_status(bd); + } + } } mutex_unlock(&bd->ops_lock); return 0; @@ -103,16 +121,16 @@ static void backlight_generate_event(struct backlight_device *bd, sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness"); } -static ssize_t backlight_show_power(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct backlight_device *bd = to_backlight_device(dev); return sprintf(buf, "%d\n", bd->props.power); } -static ssize_t backlight_store_power(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { int rc; struct backlight_device *bd = to_backlight_device(dev); @@ -136,8 +154,9 @@ static ssize_t backlight_store_power(struct device *dev, return rc; } +static DEVICE_ATTR_RW(bl_power); -static ssize_t backlight_show_brightness(struct device *dev, +static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct backlight_device *bd = to_backlight_device(dev); @@ -145,7 +164,7 @@ static ssize_t backlight_show_brightness(struct device *dev, return sprintf(buf, "%d\n", bd->props.brightness); } -static ssize_t backlight_store_brightness(struct device *dev, +static ssize_t brightness_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc; @@ -175,24 +194,27 @@ static ssize_t backlight_store_brightness(struct device *dev, return rc; } +static DEVICE_ATTR_RW(brightness); -static ssize_t backlight_show_type(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t type_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct backlight_device *bd = to_backlight_device(dev); return sprintf(buf, "%s\n", backlight_types[bd->props.type]); } +static DEVICE_ATTR_RO(type); -static ssize_t backlight_show_max_brightness(struct device *dev, +static ssize_t max_brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct backlight_device *bd = to_backlight_device(dev); return sprintf(buf, "%d\n", bd->props.max_brightness); } +static DEVICE_ATTR_RO(max_brightness); -static ssize_t backlight_show_actual_brightness(struct device *dev, +static ssize_t actual_brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc = -ENXIO; @@ -205,10 +227,12 @@ static ssize_t backlight_show_actual_brightness(struct device *dev, return rc; } +static DEVICE_ATTR_RO(actual_brightness); static struct class *backlight_class; -static int backlight_suspend(struct device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int backlight_suspend(struct device *dev) { struct backlight_device *bd = to_backlight_device(dev); @@ -235,6 +259,10 @@ static int backlight_resume(struct device *dev) return 0; } +#endif + +static SIMPLE_DEV_PM_OPS(backlight_class_dev_pm_ops, backlight_suspend, + backlight_resume); static void bl_device_release(struct device *dev) { @@ -242,16 +270,15 @@ static void bl_device_release(struct device *dev) kfree(bd); } -static struct device_attribute bl_device_attributes[] = { - __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power), - __ATTR(brightness, 0644, backlight_show_brightness, - backlight_store_brightness), - __ATTR(actual_brightness, 0444, backlight_show_actual_brightness, - NULL), - __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), - __ATTR(type, 0444, backlight_show_type, NULL), - __ATTR_NULL, +static struct attribute *bl_device_attrs[] = { + &dev_attr_bl_power.attr, + &dev_attr_brightness.attr, + &dev_attr_actual_brightness.attr, + &dev_attr_max_brightness.attr, + &dev_attr_type.attr, + NULL, }; +ATTRIBUTE_GROUPS(bl_device); /** * backlight_force_update - tell the backlight subsystem that hardware state @@ -304,7 +331,7 @@ struct backlight_device *backlight_device_register(const char *name, new_bd->dev.class = backlight_class; new_bd->dev.parent = parent; new_bd->dev.release = bl_device_release; - dev_set_name(&new_bd->dev, name); + dev_set_name(&new_bd->dev, "%s", name); dev_set_drvdata(&new_bd->dev, devdata); /* Set default properties */ @@ -321,7 +348,7 @@ struct backlight_device *backlight_device_register(const char *name, rc = device_register(&new_bd->dev); if (rc) { - kfree(new_bd); + put_device(&new_bd->dev); return ERR_PTR(rc); } @@ -340,10 +367,35 @@ struct backlight_device *backlight_device_register(const char *name, mutex_unlock(&pmac_backlight_mutex); #endif + mutex_lock(&backlight_dev_list_mutex); + list_add(&new_bd->entry, &backlight_dev_list); + mutex_unlock(&backlight_dev_list_mutex); + + blocking_notifier_call_chain(&backlight_notifier, + BACKLIGHT_REGISTERED, new_bd); + return new_bd; } EXPORT_SYMBOL(backlight_device_register); +bool backlight_device_registered(enum backlight_type type) +{ + bool found = false; + struct backlight_device *bd; + + mutex_lock(&backlight_dev_list_mutex); + list_for_each_entry(bd, &backlight_dev_list, entry) { + if (bd->props.type == type) { + found = true; + break; + } + } + mutex_unlock(&backlight_dev_list_mutex); + + return found; +} +EXPORT_SYMBOL(backlight_device_registered); + /** * backlight_device_unregister - unregisters a backlight device object. * @bd: the backlight device object to be unregistered and freed. @@ -355,12 +407,20 @@ void backlight_device_unregister(struct backlight_device *bd) if (!bd) return; + mutex_lock(&backlight_dev_list_mutex); + list_del(&bd->entry); + mutex_unlock(&backlight_dev_list_mutex); + #ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); if (pmac_backlight == bd) pmac_backlight = NULL; mutex_unlock(&pmac_backlight_mutex); #endif + + blocking_notifier_call_chain(&backlight_notifier, + BACKLIGHT_UNREGISTERED, bd); + mutex_lock(&bd->ops_lock); bd->ops = NULL; mutex_unlock(&bd->ops_lock); @@ -370,6 +430,140 @@ void backlight_device_unregister(struct backlight_device *bd) } EXPORT_SYMBOL(backlight_device_unregister); +static void devm_backlight_device_release(struct device *dev, void *res) +{ + struct backlight_device *backlight = *(struct backlight_device **)res; + + backlight_device_unregister(backlight); +} + +static int devm_backlight_device_match(struct device *dev, void *res, + void *data) +{ + struct backlight_device **r = res; + + return *r == data; +} + +/** + * backlight_register_notifier - get notified of backlight (un)registration + * @nb: notifier block with the notifier to call on backlight (un)registration + * + * @return 0 on success, otherwise a negative error code + * + * Register a notifier to get notified when backlight devices get registered + * or unregistered. + */ +int backlight_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&backlight_notifier, nb); +} +EXPORT_SYMBOL(backlight_register_notifier); + +/** + * backlight_unregister_notifier - unregister a backlight notifier + * @nb: notifier block to unregister + * + * @return 0 on success, otherwise a negative error code + * + * Register a notifier to get notified when backlight devices get registered + * or unregistered. + */ +int backlight_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&backlight_notifier, nb); +} +EXPORT_SYMBOL(backlight_unregister_notifier); + +/** + * devm_backlight_device_register - resource managed backlight_device_register() + * @dev: the device to register + * @name: the name of the device + * @parent: a pointer to the parent device + * @devdata: an optional pointer to be stored for private driver use + * @ops: the backlight operations structure + * @props: the backlight properties + * + * @return a struct backlight on success, or an ERR_PTR on error + * + * Managed backlight_device_register(). The backlight_device returned + * from this function are automatically freed on driver detach. + * See backlight_device_register() for more information. + */ +struct backlight_device *devm_backlight_device_register(struct device *dev, + const char *name, struct device *parent, void *devdata, + const struct backlight_ops *ops, + const struct backlight_properties *props) +{ + struct backlight_device **ptr, *backlight; + + ptr = devres_alloc(devm_backlight_device_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + backlight = backlight_device_register(name, parent, devdata, ops, + props); + if (!IS_ERR(backlight)) { + *ptr = backlight; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return backlight; +} +EXPORT_SYMBOL(devm_backlight_device_register); + +/** + * devm_backlight_device_unregister - resource managed backlight_device_unregister() + * @dev: the device to unregister + * @bd: the backlight device to unregister + * + * Deallocated a backlight allocated with devm_backlight_device_register(). + * Normally this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_backlight_device_unregister(struct device *dev, + struct backlight_device *bd) +{ + int rc; + + rc = devres_release(dev, devm_backlight_device_release, + devm_backlight_device_match, bd); + WARN_ON(rc); +} +EXPORT_SYMBOL(devm_backlight_device_unregister); + +#ifdef CONFIG_OF +static int of_parent_match(struct device *dev, const void *data) +{ + return dev->parent && dev->parent->of_node == data; +} + +/** + * of_find_backlight_by_node() - find backlight device by device-tree node + * @node: device-tree node of the backlight device + * + * Returns a pointer to the backlight device corresponding to the given DT + * node or NULL if no such backlight device exists or if the device hasn't + * been probed yet. + * + * This function obtains a reference on the backlight device and it is the + * caller's responsibility to drop the reference by calling put_device() on + * the backlight device's .dev field. + */ +struct backlight_device *of_find_backlight_by_node(struct device_node *node) +{ + struct device *dev; + + dev = class_find_device(backlight_class, NULL, node, of_parent_match); + + return dev ? to_backlight_device(dev) : NULL; +} +EXPORT_SYMBOL(of_find_backlight_by_node); +#endif + static void __exit backlight_class_exit(void) { class_destroy(backlight_class); @@ -384,9 +578,12 @@ static int __init backlight_class_init(void) return PTR_ERR(backlight_class); } - backlight_class->dev_attrs = bl_device_attributes; - backlight_class->suspend = backlight_suspend; - backlight_class->resume = backlight_resume; + backlight_class->dev_groups = bl_device_groups; + backlight_class->pm = &backlight_class_dev_pm_ops; + INIT_LIST_HEAD(&backlight_dev_list); + mutex_init(&backlight_dev_list_mutex); + BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier); + return 0; } diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c new file mode 100644 index 00000000000..16dd9bc625b --- /dev/null +++ b/drivers/video/backlight/bd6107.c @@ -0,0 +1,213 @@ +/* + * ROHM Semiconductor BD6107 LED Driver + * + * Copyright (C) 2013 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/platform_data/bd6107.h> +#include <linux/slab.h> + +#define BD6107_PSCNT1 0x00 +#define BD6107_PSCNT1_PSCNTREG2 (1 << 2) +#define BD6107_PSCNT1_PSCNTREG1 (1 << 0) +#define BD6107_REGVSET 0x02 +#define BD6107_REGVSET_REG1VSET_2_85V (1 << 2) +#define BD6107_REGVSET_REG1VSET_2_80V (0 << 2) +#define BD6107_LEDCNT1 0x03 +#define BD6107_LEDCNT1_LEDONOFF2 (1 << 1) +#define BD6107_LEDCNT1_LEDONOFF1 (1 << 0) +#define BD6107_PORTSEL 0x04 +#define BD6107_PORTSEL_LEDM(n) (1 << (n)) +#define BD6107_RGB1CNT1 0x05 +#define BD6107_RGB1CNT2 0x06 +#define BD6107_RGB1CNT3 0x07 +#define BD6107_RGB1CNT4 0x08 +#define BD6107_RGB1CNT5 0x09 +#define BD6107_RGB1FLM 0x0a +#define BD6107_RGB2CNT1 0x0b +#define BD6107_RGB2CNT2 0x0c +#define BD6107_RGB2CNT3 0x0d +#define BD6107_RGB2CNT4 0x0e +#define BD6107_RGB2CNT5 0x0f +#define BD6107_RGB2FLM 0x10 +#define BD6107_PSCONT3 0x11 +#define BD6107_SMMONCNT 0x12 +#define BD6107_DCDCCNT 0x13 +#define BD6107_IOSEL 0x14 +#define BD6107_OUT1 0x15 +#define BD6107_OUT2 0x16 +#define BD6107_MASK1 0x17 +#define BD6107_MASK2 0x18 +#define BD6107_FACTOR1 0x19 +#define BD6107_FACTOR2 0x1a +#define BD6107_CLRFACT1 0x1b +#define BD6107_CLRFACT2 0x1c +#define BD6107_STATE1 0x1d +#define BD6107_LSIVER 0x1e +#define BD6107_GRPSEL 0x1f +#define BD6107_LEDCNT2 0x20 +#define BD6107_LEDCNT3 0x21 +#define BD6107_MCURRENT 0x22 +#define BD6107_MAINCNT1 0x23 +#define BD6107_MAINCNT2 0x24 +#define BD6107_SLOPECNT 0x25 +#define BD6107_MSLOPE 0x26 +#define BD6107_RGBSLOPE 0x27 +#define BD6107_TEST 0x29 +#define BD6107_SFTRST 0x2a +#define BD6107_SFTRSTGD 0x2b + +struct bd6107 { + struct i2c_client *client; + struct backlight_device *backlight; + struct bd6107_platform_data *pdata; +}; + +static int bd6107_write(struct bd6107 *bd, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(bd->client, reg, data); +} + +static int bd6107_backlight_update_status(struct backlight_device *backlight) +{ + struct bd6107 *bd = bl_get_data(backlight); + int brightness = backlight->props.brightness; + + if (backlight->props.power != FB_BLANK_UNBLANK || + backlight->props.fb_blank != FB_BLANK_UNBLANK || + backlight->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + if (brightness) { + bd6107_write(bd, BD6107_PORTSEL, BD6107_PORTSEL_LEDM(2) | + BD6107_PORTSEL_LEDM(1) | BD6107_PORTSEL_LEDM(0)); + bd6107_write(bd, BD6107_MAINCNT1, brightness); + bd6107_write(bd, BD6107_LEDCNT1, BD6107_LEDCNT1_LEDONOFF1); + } else { + gpio_set_value(bd->pdata->reset, 0); + msleep(24); + gpio_set_value(bd->pdata->reset, 1); + } + + return 0; +} + +static int bd6107_backlight_get_brightness(struct backlight_device *backlight) +{ + return backlight->props.brightness; +} + +static int bd6107_backlight_check_fb(struct backlight_device *backlight, + struct fb_info *info) +{ + struct bd6107 *bd = bl_get_data(backlight); + + return bd->pdata->fbdev == NULL || bd->pdata->fbdev == info->dev; +} + +static const struct backlight_ops bd6107_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = bd6107_backlight_update_status, + .get_brightness = bd6107_backlight_get_brightness, + .check_fb = bd6107_backlight_check_fb, +}; + +static int bd6107_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bd6107_platform_data *pdata = dev_get_platdata(&client->dev); + struct backlight_device *backlight; + struct backlight_properties props; + struct bd6107 *bd; + int ret; + + if (pdata == NULL || !pdata->reset) { + dev_err(&client->dev, "No reset GPIO in platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&client->dev, + "I2C adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL); + if (!bd) + return -ENOMEM; + + bd->client = client; + bd->pdata = pdata; + + ret = devm_gpio_request_one(&client->dev, pdata->reset, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, "reset"); + if (ret < 0) { + dev_err(&client->dev, "unable to request reset GPIO\n"); + return ret; + } + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 128; + props.brightness = clamp_t(unsigned int, pdata->def_value, 0, + props.max_brightness); + + backlight = devm_backlight_device_register(&client->dev, + dev_name(&client->dev), + &bd->client->dev, bd, + &bd6107_backlight_ops, &props); + if (IS_ERR(backlight)) { + dev_err(&client->dev, "failed to register backlight\n"); + return PTR_ERR(backlight); + } + + backlight_update_status(backlight); + i2c_set_clientdata(client, backlight); + + return 0; +} + +static int bd6107_remove(struct i2c_client *client) +{ + struct backlight_device *backlight = i2c_get_clientdata(client); + + backlight->props.brightness = 0; + backlight_update_status(backlight); + + return 0; +} + +static const struct i2c_device_id bd6107_ids[] = { + { "bd6107", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bd6107_ids); + +static struct i2c_driver bd6107_driver = { + .driver = { + .name = "bd6107", + }, + .probe = bd6107_probe, + .remove = bd6107_remove, + .id_table = bd6107_ids, +}; + +module_i2c_driver(bd6107_driver); + +MODULE_DESCRIPTION("Rohm BD6107 Backlight Driver"); +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 23d732677ba..51d18d637e2 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -6,8 +6,8 @@ * Based on Sharp's 2.4 Backlight Driver * * Copyright (c) 2008 Marvell International Ltd. - * Converted to SPI device based LCD/Backlight device driver - * by Eric Miao <eric.miao@marvell.com> + * Converted to SPI device based LCD/Backlight device driver + * by Eric Miao <eric.miao@marvell.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -192,7 +192,7 @@ static void lcdtg_set_phadadj(struct corgi_lcd *lcd, int mode) { int adj; - switch(mode) { + switch (mode) { case CORGI_LCD_MODE_VGA: /* Setting for VGA */ adj = sharpsl_param.phadadj; @@ -337,7 +337,7 @@ static void corgi_lcd_power_off(struct corgi_lcd *lcd) static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m) { - struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); + struct corgi_lcd *lcd = lcd_get_data(ld); int mode = CORGI_LCD_MODE_QVGA; if (m->xres == 640 || m->xres == 480) @@ -364,7 +364,7 @@ static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m) static int corgi_lcd_set_power(struct lcd_device *ld, int power) { - struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); + struct corgi_lcd *lcd = lcd_get_data(ld); if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) corgi_lcd_power_on(lcd); @@ -378,7 +378,7 @@ static int corgi_lcd_set_power(struct lcd_device *ld, int power) static int corgi_lcd_get_power(struct lcd_device *ld) { - struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); + struct corgi_lcd *lcd = lcd_get_data(ld); return lcd->power; } @@ -391,7 +391,7 @@ static struct lcd_ops corgi_lcd_ops = { static int corgi_bl_get_intensity(struct backlight_device *bd) { - struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev); + struct corgi_lcd *lcd = bl_get_data(bd); return lcd->intensity; } @@ -409,10 +409,10 @@ static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity) cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted; if (gpio_is_valid(lcd->gpio_backlight_cont)) - gpio_set_value(lcd->gpio_backlight_cont, cont); + gpio_set_value_cansleep(lcd->gpio_backlight_cont, cont); if (gpio_is_valid(lcd->gpio_backlight_on)) - gpio_set_value(lcd->gpio_backlight_on, intensity); + gpio_set_value_cansleep(lcd->gpio_backlight_on, intensity); if (lcd->kick_battery) lcd->kick_battery(); @@ -423,7 +423,7 @@ static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity) static int corgi_bl_update_status(struct backlight_device *bd) { - struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev); + struct corgi_lcd *lcd = bl_get_data(bd); int intensity = bd->props.brightness; if (bd->props.power != FB_BLANK_UNBLANK) @@ -457,10 +457,10 @@ static const struct backlight_ops corgi_bl_ops = { .update_status = corgi_bl_update_status, }; -#ifdef CONFIG_PM -static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int corgi_lcd_suspend(struct device *dev) { - struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); + struct corgi_lcd *lcd = dev_get_drvdata(dev); corgibl_flags |= CORGIBL_SUSPENDED; corgi_bl_set_intensity(lcd, 0); @@ -468,20 +468,19 @@ static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state) return 0; } -static int corgi_lcd_resume(struct spi_device *spi) +static int corgi_lcd_resume(struct device *dev) { - struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); + struct corgi_lcd *lcd = dev_get_drvdata(dev); corgibl_flags &= ~CORGIBL_SUSPENDED; corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); backlight_update_status(lcd->bl_dev); return 0; } -#else -#define corgi_lcd_suspend NULL -#define corgi_lcd_resume NULL #endif +static SIMPLE_DEV_PM_OPS(corgi_lcd_pm_ops, corgi_lcd_suspend, corgi_lcd_resume); + static int setup_gpio_backlight(struct corgi_lcd *lcd, struct corgi_lcd_platform_data *pdata) { @@ -492,10 +491,12 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd, lcd->gpio_backlight_cont = -1; if (gpio_is_valid(pdata->gpio_backlight_on)) { - err = gpio_request(pdata->gpio_backlight_on, "BL_ON"); + err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_on, + "BL_ON"); if (err) { - dev_err(&spi->dev, "failed to request GPIO%d for " - "backlight_on\n", pdata->gpio_backlight_on); + dev_err(&spi->dev, + "failed to request GPIO%d for backlight_on\n", + pdata->gpio_backlight_on); return err; } @@ -504,11 +505,13 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd, } if (gpio_is_valid(pdata->gpio_backlight_cont)) { - err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT"); + err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_cont, + "BL_CONT"); if (err) { - dev_err(&spi->dev, "failed to request GPIO%d for " - "backlight_cont\n", pdata->gpio_backlight_cont); - goto err_free_backlight_on; + dev_err(&spi->dev, + "failed to request GPIO%d for backlight_cont\n", + pdata->gpio_backlight_cont); + return err; } lcd->gpio_backlight_cont = pdata->gpio_backlight_cont; @@ -525,17 +528,12 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd, } } return 0; - -err_free_backlight_on: - if (gpio_is_valid(lcd->gpio_backlight_on)) - gpio_free(lcd->gpio_backlight_on); - return err; } -static int __devinit corgi_lcd_probe(struct spi_device *spi) +static int corgi_lcd_probe(struct spi_device *spi) { struct backlight_properties props; - struct corgi_lcd_platform_data *pdata = spi->dev.platform_data; + struct corgi_lcd_platform_data *pdata = dev_get_platdata(&spi->dev); struct corgi_lcd *lcd; int ret = 0; @@ -545,15 +543,13 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi) } lcd = devm_kzalloc(&spi->dev, sizeof(struct corgi_lcd), GFP_KERNEL); - if (!lcd) { - dev_err(&spi->dev, "failed to allocate memory\n"); + if (!lcd) return -ENOMEM; - } lcd->spi_dev = spi; - lcd->lcd_dev = lcd_device_register("corgi_lcd", &spi->dev, - lcd, &corgi_lcd_ops); + lcd->lcd_dev = devm_lcd_device_register(&spi->dev, "corgi_lcd", + &spi->dev, lcd, &corgi_lcd_ops); if (IS_ERR(lcd->lcd_dev)) return PTR_ERR(lcd->lcd_dev); @@ -563,54 +559,38 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = pdata->max_intensity; - lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd, - &corgi_bl_ops, &props); - if (IS_ERR(lcd->bl_dev)) { - ret = PTR_ERR(lcd->bl_dev); - goto err_unregister_lcd; - } + lcd->bl_dev = devm_backlight_device_register(&spi->dev, "corgi_bl", + &spi->dev, lcd, &corgi_bl_ops, + &props); + if (IS_ERR(lcd->bl_dev)) + return PTR_ERR(lcd->bl_dev); + lcd->bl_dev->props.brightness = pdata->default_intensity; lcd->bl_dev->props.power = FB_BLANK_UNBLANK; ret = setup_gpio_backlight(lcd, pdata); if (ret) - goto err_unregister_bl; + return ret; lcd->kick_battery = pdata->kick_battery; - dev_set_drvdata(&spi->dev, lcd); + spi_set_drvdata(spi, lcd); corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); backlight_update_status(lcd->bl_dev); lcd->limit_mask = pdata->limit_mask; the_corgi_lcd = lcd; return 0; - -err_unregister_bl: - backlight_device_unregister(lcd->bl_dev); -err_unregister_lcd: - lcd_device_unregister(lcd->lcd_dev); - return ret; } -static int __devexit corgi_lcd_remove(struct spi_device *spi) +static int corgi_lcd_remove(struct spi_device *spi) { - struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); + struct corgi_lcd *lcd = spi_get_drvdata(spi); lcd->bl_dev->props.power = FB_BLANK_UNBLANK; lcd->bl_dev->props.brightness = 0; backlight_update_status(lcd->bl_dev); - backlight_device_unregister(lcd->bl_dev); - - if (gpio_is_valid(lcd->gpio_backlight_on)) - gpio_free(lcd->gpio_backlight_on); - - if (gpio_is_valid(lcd->gpio_backlight_cont)) - gpio_free(lcd->gpio_backlight_cont); - corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->lcd_dev); - return 0; } @@ -618,11 +598,10 @@ static struct spi_driver corgi_lcd_driver = { .driver = { .name = "corgi-lcd", .owner = THIS_MODULE, + .pm = &corgi_lcd_pm_ops, }, .probe = corgi_lcd_probe, - .remove = __devexit_p(corgi_lcd_remove), - .suspend = corgi_lcd_suspend, - .resume = corgi_lcd_resume, + .remove = corgi_lcd_remove, }; module_spi_driver(corgi_lcd_driver); diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 37bae801e23..f3fed9ef745 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -195,16 +195,17 @@ static int cr_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; - bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL, - &cr_backlight_ops, &props); + bdp = devm_backlight_device_register(&pdev->dev, "cr-backlight", + &pdev->dev, NULL, &cr_backlight_ops, + &props); if (IS_ERR(bdp)) { pci_dev_put(lpc_dev); return PTR_ERR(bdp); } - ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops); + ldp = devm_lcd_device_register(&pdev->dev, "cr-lcd", &pdev->dev, NULL, + &cr_lcd_ops); if (IS_ERR(ldp)) { - backlight_device_unregister(bdp); pci_dev_put(lpc_dev); return PTR_ERR(ldp); } @@ -215,8 +216,6 @@ static int cr_backlight_probe(struct platform_device *pdev) crp = devm_kzalloc(&pdev->dev, sizeof(*crp), GFP_KERNEL); if (!crp) { - lcd_device_unregister(ldp); - backlight_device_unregister(bdp); pci_dev_put(lpc_dev); return -ENOMEM; } @@ -241,8 +240,6 @@ static int cr_backlight_remove(struct platform_device *pdev) crp->cr_backlight_device->props.max_brightness = 0; cr_backlight_set_intensity(crp->cr_backlight_device); cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN); - backlight_device_unregister(crp->cr_backlight_device); - lcd_device_unregister(crp->cr_lcd_device); pci_dev_put(lpc_dev); return 0; diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 573c7ece0fd..12c5d840c59 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -2,10 +2,10 @@ * Backlight driver for Dialog Semiconductor DA9030/DA9034 * * Copyright (C) 2008 Compulab, Ltd. - * Mike Rapoport <mike@compulab.co.il> + * Mike Rapoport <mike@compulab.co.il> * * Copyright (C) 2006-2008 Marvell International Ltd. - * Eric Miao <eric.miao@marvell.com> + * Eric Miao <eric.miao@marvell.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -88,23 +88,28 @@ static int da903x_backlight_update_status(struct backlight_device *bl) if (bl->props.fb_blank != FB_BLANK_UNBLANK) brightness = 0; + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + return da903x_backlight_set(bl, brightness); } static int da903x_backlight_get_brightness(struct backlight_device *bl) { struct da903x_backlight_data *data = bl_get_data(bl); + return data->current_brightness; } static const struct backlight_ops da903x_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, .update_status = da903x_backlight_update_status, .get_brightness = da903x_backlight_get_brightness, }; static int da903x_backlight_probe(struct platform_device *pdev) { - struct da9034_backlight_pdata *pdata = pdev->dev.platform_data; + struct da9034_backlight_pdata *pdata = dev_get_platdata(&pdev->dev); struct da903x_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; @@ -139,8 +144,9 @@ static int da903x_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = max_brightness; - bl = backlight_device_register(pdev->name, data->da903x_dev, data, - &da903x_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, + data->da903x_dev, data, + &da903x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -153,53 +159,18 @@ static int da903x_backlight_probe(struct platform_device *pdev) return 0; } -static int da903x_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; -} - -#ifdef CONFIG_PM -static int da903x_backlight_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct backlight_device *bl = platform_get_drvdata(pdev); - return da903x_backlight_set(bl, 0); -} - -static int da903x_backlight_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_update_status(bl); - return 0; -} - -static const struct dev_pm_ops da903x_backlight_pm_ops = { - .suspend = da903x_backlight_suspend, - .resume = da903x_backlight_resume, -}; -#endif - static struct platform_driver da903x_backlight_driver = { .driver = { .name = "da903x-backlight", .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &da903x_backlight_pm_ops, -#endif }, .probe = da903x_backlight_probe, - .remove = da903x_backlight_remove, }; module_platform_driver(da903x_backlight_driver); MODULE_DESCRIPTION("Backlight Driver for Dialog Semiconductor DA9030/DA9034"); -MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>" - "Mike Rapoport <mike@compulab.co.il>"); +MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); +MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:da903x-backlight"); diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index b628d68f516..20d55becaa7 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -34,7 +34,7 @@ enum { DA9052_TYPE_WLED3, }; -static unsigned char wled_bank[] = { +static const unsigned char wled_bank[] = { DA9052_LED1_CONF_REG, DA9052_LED2_CONF_REG, DA9052_LED3_CONF_REG, @@ -72,7 +72,7 @@ static int da9052_adjust_wled_brightness(struct da9052_bl *wleds) if (ret < 0) return ret; - msleep(10); + usleep_range(10000, 11000); if (wleds->brightness) { ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg], @@ -125,11 +125,11 @@ static int da9052_backlight_probe(struct platform_device *pdev) props.type = BACKLIGHT_RAW; props.max_brightness = DA9052_MAX_BRIGHTNESS; - bl = backlight_device_register(pdev->name, wleds->da9052->dev, wleds, - &da9052_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, + wleds->da9052->dev, wleds, + &da9052_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "Failed to register backlight\n"); - devm_kfree(&pdev->dev, wleds); return PTR_ERR(bl); } @@ -148,8 +148,6 @@ static int da9052_backlight_remove(struct platform_device *pdev) wleds->brightness = 0; wleds->state = DA9052_WLEDS_OFF; da9052_adjust_wled_brightness(wleds); - backlight_device_unregister(bl); - devm_kfree(&pdev->dev, wleds); return 0; } diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index 08214e1f095..0d1f633c648 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -60,7 +60,7 @@ static const struct backlight_ops ep93xxbl_ops = { .get_brightness = ep93xxbl_get_brightness, }; -static int __init ep93xxbl_probe(struct platform_device *dev) +static int ep93xxbl_probe(struct platform_device *dev) { struct ep93xxbl *ep93xxbl; struct backlight_device *bl; @@ -92,8 +92,8 @@ static int __init ep93xxbl_probe(struct platform_device *dev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = EP93XX_MAX_BRIGHT; - bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, - &ep93xxbl_ops, &props); + bl = devm_backlight_device_register(&dev->dev, dev->name, &dev->dev, + ep93xxbl, &ep93xxbl_ops, &props); if (IS_ERR(bl)) return PTR_ERR(bl); @@ -106,44 +106,32 @@ static int __init ep93xxbl_probe(struct platform_device *dev) return 0; } -static int ep93xxbl_remove(struct platform_device *dev) +#ifdef CONFIG_PM_SLEEP +static int ep93xxbl_suspend(struct device *dev) { - struct backlight_device *bl = platform_get_drvdata(dev); - - backlight_device_unregister(bl); - platform_set_drvdata(dev, NULL); - return 0; -} - -#ifdef CONFIG_PM -static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state) -{ - struct backlight_device *bl = platform_get_drvdata(dev); + struct backlight_device *bl = dev_get_drvdata(dev); return ep93xxbl_set(bl, 0); } -static int ep93xxbl_resume(struct platform_device *dev) +static int ep93xxbl_resume(struct device *dev) { - struct backlight_device *bl = platform_get_drvdata(dev); + struct backlight_device *bl = dev_get_drvdata(dev); backlight_update_status(bl); return 0; } -#else -#define ep93xxbl_suspend NULL -#define ep93xxbl_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ep93xxbl_pm_ops, ep93xxbl_suspend, ep93xxbl_resume); + static struct platform_driver ep93xxbl_driver = { .driver = { .name = "ep93xx-bl", .owner = THIS_MODULE, + .pm = &ep93xxbl_pm_ops, }, .probe = ep93xxbl_probe, - .remove = __devexit_p(ep93xxbl_remove), - .suspend = ep93xxbl_suspend, - .resume = ep93xxbl_resume, }; module_platform_driver(ep93xxbl_driver); diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 8c660fcd250..5d8d65200db 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -9,8 +9,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -81,7 +79,7 @@ static const struct backlight_ops genericbl_ops = { static int genericbl_probe(struct platform_device *pdev) { struct backlight_properties props; - struct generic_bl_info *machinfo = pdev->dev.platform_data; + struct generic_bl_info *machinfo = dev_get_platdata(&pdev->dev); const char *name = "generic-bl"; struct backlight_device *bd; @@ -95,10 +93,10 @@ static int genericbl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; - bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops, - &props); - if (IS_ERR (bd)) - return PTR_ERR (bd); + bd = devm_backlight_device_register(&pdev->dev, name, &pdev->dev, + NULL, &genericbl_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); platform_set_drvdata(pdev, bd); @@ -108,7 +106,7 @@ static int genericbl_probe(struct platform_device *pdev) generic_backlight_device = bd; - pr_info("Generic Backlight Driver Initialized.\n"); + dev_info(&pdev->dev, "Generic Backlight Driver Initialized.\n"); return 0; } @@ -120,9 +118,7 @@ static int genericbl_remove(struct platform_device *pdev) bd->props.brightness = 0; backlight_update_status(bd); - backlight_device_unregister(bd); - - pr_info("Generic Backlight Driver Unloaded\n"); + dev_info(&pdev->dev, "Generic Backlight Driver Unloaded\n"); return 0; } diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c new file mode 100644 index 00000000000..1cea68848f1 --- /dev/null +++ b/drivers/video/backlight/gpio_backlight.c @@ -0,0 +1,171 @@ +/* + * gpio_backlight.c - Simple GPIO-controlled backlight + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_data/gpio_backlight.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct gpio_backlight { + struct device *dev; + struct device *fbdev; + + int gpio; + int active; + int def_value; +}; + +static int gpio_backlight_update_status(struct backlight_device *bl) +{ + struct gpio_backlight *gbl = bl_get_data(bl); + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + gpio_set_value_cansleep(gbl->gpio, + brightness ? gbl->active : !gbl->active); + + return 0; +} + +static int gpio_backlight_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static int gpio_backlight_check_fb(struct backlight_device *bl, + struct fb_info *info) +{ + struct gpio_backlight *gbl = bl_get_data(bl); + + return gbl->fbdev == NULL || gbl->fbdev == info->dev; +} + +static const struct backlight_ops gpio_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = gpio_backlight_update_status, + .get_brightness = gpio_backlight_get_brightness, + .check_fb = gpio_backlight_check_fb, +}; + +static int gpio_backlight_probe_dt(struct platform_device *pdev, + struct gpio_backlight *gbl) +{ + struct device_node *np = pdev->dev.of_node; + enum of_gpio_flags gpio_flags; + + gbl->gpio = of_get_gpio_flags(np, 0, &gpio_flags); + + if (!gpio_is_valid(gbl->gpio)) { + if (gbl->gpio != -EPROBE_DEFER) { + dev_err(&pdev->dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + return gbl->gpio; + } + + gbl->active = (gpio_flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; + + gbl->def_value = of_property_read_bool(np, "default-on"); + + return 0; +} + +static int gpio_backlight_probe(struct platform_device *pdev) +{ + struct gpio_backlight_platform_data *pdata = + dev_get_platdata(&pdev->dev); + struct backlight_properties props; + struct backlight_device *bl; + struct gpio_backlight *gbl; + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!pdata && !np) { + dev_err(&pdev->dev, + "failed to find platform data or device tree node.\n"); + return -ENODEV; + } + + gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL); + if (gbl == NULL) + return -ENOMEM; + + gbl->dev = &pdev->dev; + + if (np) { + ret = gpio_backlight_probe_dt(pdev, gbl); + if (ret) + return ret; + } else { + gbl->fbdev = pdata->fbdev; + gbl->gpio = pdata->gpio; + gbl->active = pdata->active_low ? 0 : 1; + gbl->def_value = pdata->def_value; + } + + ret = devm_gpio_request_one(gbl->dev, gbl->gpio, GPIOF_DIR_OUT | + (gbl->active ? GPIOF_INIT_LOW + : GPIOF_INIT_HIGH), + pdata ? pdata->name : "backlight"); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request GPIO\n"); + return ret; + } + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 1; + bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev), + &pdev->dev, gbl, &gpio_backlight_ops, + &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } + + bl->props.brightness = gbl->def_value; + backlight_update_status(bl); + + platform_set_drvdata(pdev, bl); + return 0; +} + +#ifdef CONFIG_OF +static struct of_device_id gpio_backlight_of_match[] = { + { .compatible = "gpio-backlight" }, + { /* sentinel */ } +}; +#endif + +static struct platform_driver gpio_backlight_driver = { + .driver = { + .name = "gpio-backlight", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gpio_backlight_of_match), + }, + .probe = gpio_backlight_probe, +}; + +module_platform_driver(gpio_backlight_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("GPIO-based Backlight Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-backlight"); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 38aa0027214..8ea42b8d9bc 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -26,7 +26,7 @@ #define HP680_DEFAULT_INTENSITY 10 static int hp680bl_suspended; -static int current_intensity = 0; +static int current_intensity; static DEFINE_SPINLOCK(bl_lock); static void hp680bl_send_intensity(struct backlight_device *bd) @@ -64,29 +64,28 @@ static void hp680bl_send_intensity(struct backlight_device *bd) } -#ifdef CONFIG_PM -static int hp680bl_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int hp680bl_suspend(struct device *dev) { - struct backlight_device *bd = platform_get_drvdata(pdev); + struct backlight_device *bd = dev_get_drvdata(dev); hp680bl_suspended = 1; hp680bl_send_intensity(bd); return 0; } -static int hp680bl_resume(struct platform_device *pdev) +static int hp680bl_resume(struct device *dev) { - struct backlight_device *bd = platform_get_drvdata(pdev); + struct backlight_device *bd = dev_get_drvdata(dev); hp680bl_suspended = 0; hp680bl_send_intensity(bd); return 0; } -#else -#define hp680bl_suspend NULL -#define hp680bl_resume NULL #endif +static SIMPLE_DEV_PM_OPS(hp680bl_pm_ops, hp680bl_suspend, hp680bl_resume); + static int hp680bl_set_intensity(struct backlight_device *bd) { hp680bl_send_intensity(bd); @@ -103,7 +102,7 @@ static const struct backlight_ops hp680bl_ops = { .update_status = hp680bl_set_intensity, }; -static int __devinit hp680bl_probe(struct platform_device *pdev) +static int hp680bl_probe(struct platform_device *pdev) { struct backlight_properties props; struct backlight_device *bd; @@ -111,8 +110,8 @@ static int __devinit hp680bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = HP680_MAX_INTENSITY; - bd = backlight_device_register("hp680-bl", &pdev->dev, NULL, - &hp680bl_ops, &props); + bd = devm_backlight_device_register(&pdev->dev, "hp680-bl", &pdev->dev, + NULL, &hp680bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -132,18 +131,15 @@ static int hp680bl_remove(struct platform_device *pdev) bd->props.power = 0; hp680bl_send_intensity(bd); - backlight_device_unregister(bd); - return 0; } static struct platform_driver hp680bl_driver = { .probe = hp680bl_probe, .remove = hp680bl_remove, - .suspend = hp680bl_suspend, - .resume = hp680bl_resume, .driver = { .name = "hp680-bl", + .pm = &hp680bl_pm_ops, }, }; @@ -168,7 +164,7 @@ static int __init hp680bl_init(void) static void __exit hp680bl_exit(void) { platform_device_unregister(hp680bl_device); - platform_driver_unregister(&hp680bl_driver); + platform_driver_unregister(&hp680bl_driver); } module_init(hp680bl_init); diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c new file mode 100644 index 00000000000..23f50b92a93 --- /dev/null +++ b/drivers/video/backlight/hx8357.c @@ -0,0 +1,682 @@ +/* + * Driver for the Himax HX-8357 LCD Controller + * + * Copyright 2012 Free Electrons + * + * Licensed under the GPLv2 or later. + */ + +#include <linux/delay.h> +#include <linux/lcd.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/spi/spi.h> + +#define HX8357_NUM_IM_PINS 3 + +#define HX8357_SWRESET 0x01 +#define HX8357_GET_RED_CHANNEL 0x06 +#define HX8357_GET_GREEN_CHANNEL 0x07 +#define HX8357_GET_BLUE_CHANNEL 0x08 +#define HX8357_GET_POWER_MODE 0x0a +#define HX8357_GET_MADCTL 0x0b +#define HX8357_GET_PIXEL_FORMAT 0x0c +#define HX8357_GET_DISPLAY_MODE 0x0d +#define HX8357_GET_SIGNAL_MODE 0x0e +#define HX8357_GET_DIAGNOSTIC_RESULT 0x0f +#define HX8357_ENTER_SLEEP_MODE 0x10 +#define HX8357_EXIT_SLEEP_MODE 0x11 +#define HX8357_ENTER_PARTIAL_MODE 0x12 +#define HX8357_ENTER_NORMAL_MODE 0x13 +#define HX8357_EXIT_INVERSION_MODE 0x20 +#define HX8357_ENTER_INVERSION_MODE 0x21 +#define HX8357_SET_DISPLAY_OFF 0x28 +#define HX8357_SET_DISPLAY_ON 0x29 +#define HX8357_SET_COLUMN_ADDRESS 0x2a +#define HX8357_SET_PAGE_ADDRESS 0x2b +#define HX8357_WRITE_MEMORY_START 0x2c +#define HX8357_READ_MEMORY_START 0x2e +#define HX8357_SET_PARTIAL_AREA 0x30 +#define HX8357_SET_SCROLL_AREA 0x33 +#define HX8357_SET_TEAR_OFF 0x34 +#define HX8357_SET_TEAR_ON 0x35 +#define HX8357_SET_ADDRESS_MODE 0x36 +#define HX8357_SET_SCROLL_START 0x37 +#define HX8357_EXIT_IDLE_MODE 0x38 +#define HX8357_ENTER_IDLE_MODE 0x39 +#define HX8357_SET_PIXEL_FORMAT 0x3a +#define HX8357_SET_PIXEL_FORMAT_DBI_3BIT (0x1) +#define HX8357_SET_PIXEL_FORMAT_DBI_16BIT (0x5) +#define HX8357_SET_PIXEL_FORMAT_DBI_18BIT (0x6) +#define HX8357_SET_PIXEL_FORMAT_DPI_3BIT (0x1 << 4) +#define HX8357_SET_PIXEL_FORMAT_DPI_16BIT (0x5 << 4) +#define HX8357_SET_PIXEL_FORMAT_DPI_18BIT (0x6 << 4) +#define HX8357_WRITE_MEMORY_CONTINUE 0x3c +#define HX8357_READ_MEMORY_CONTINUE 0x3e +#define HX8357_SET_TEAR_SCAN_LINES 0x44 +#define HX8357_GET_SCAN_LINES 0x45 +#define HX8357_READ_DDB_START 0xa1 +#define HX8357_SET_DISPLAY_MODE 0xb4 +#define HX8357_SET_DISPLAY_MODE_RGB_THROUGH (0x3) +#define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE (1 << 4) +#define HX8357_SET_PANEL_DRIVING 0xc0 +#define HX8357_SET_DISPLAY_FRAME 0xc5 +#define HX8357_SET_RGB 0xc6 +#define HX8357_SET_RGB_ENABLE_HIGH (1 << 1) +#define HX8357_SET_GAMMA 0xc8 +#define HX8357_SET_POWER 0xd0 +#define HX8357_SET_VCOM 0xd1 +#define HX8357_SET_POWER_NORMAL 0xd2 +#define HX8357_SET_PANEL_RELATED 0xe9 + +#define HX8369_SET_DISPLAY_BRIGHTNESS 0x51 +#define HX8369_WRITE_CABC_DISPLAY_VALUE 0x53 +#define HX8369_WRITE_CABC_BRIGHT_CTRL 0x55 +#define HX8369_WRITE_CABC_MIN_BRIGHTNESS 0x5e +#define HX8369_SET_POWER 0xb1 +#define HX8369_SET_DISPLAY_MODE 0xb2 +#define HX8369_SET_DISPLAY_WAVEFORM_CYC 0xb4 +#define HX8369_SET_VCOM 0xb6 +#define HX8369_SET_EXTENSION_COMMAND 0xb9 +#define HX8369_SET_GIP 0xd5 +#define HX8369_SET_GAMMA_CURVE_RELATED 0xe0 + +struct hx8357_data { + unsigned im_pins[HX8357_NUM_IM_PINS]; + unsigned reset; + struct spi_device *spi; + int state; + bool use_im_pins; +}; + +static u8 hx8357_seq_power[] = { + HX8357_SET_POWER, 0x44, 0x41, 0x06, +}; + +static u8 hx8357_seq_vcom[] = { + HX8357_SET_VCOM, 0x40, 0x10, +}; + +static u8 hx8357_seq_power_normal[] = { + HX8357_SET_POWER_NORMAL, 0x05, 0x12, +}; + +static u8 hx8357_seq_panel_driving[] = { + HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11, +}; + +static u8 hx8357_seq_display_frame[] = { + HX8357_SET_DISPLAY_FRAME, 0x0c, +}; + +static u8 hx8357_seq_panel_related[] = { + HX8357_SET_PANEL_RELATED, 0x01, +}; + +static u8 hx8357_seq_undefined1[] = { + 0xea, 0x03, 0x00, 0x00, +}; + +static u8 hx8357_seq_undefined2[] = { + 0xeb, 0x40, 0x54, 0x26, 0xdb, +}; + +static u8 hx8357_seq_gamma[] = { + HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00, + 0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00, +}; + +static u8 hx8357_seq_address_mode[] = { + HX8357_SET_ADDRESS_MODE, 0xc0, +}; + +static u8 hx8357_seq_pixel_format[] = { + HX8357_SET_PIXEL_FORMAT, + HX8357_SET_PIXEL_FORMAT_DPI_18BIT | + HX8357_SET_PIXEL_FORMAT_DBI_18BIT, +}; + +static u8 hx8357_seq_column_address[] = { + HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f, +}; + +static u8 hx8357_seq_page_address[] = { + HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf, +}; + +static u8 hx8357_seq_rgb[] = { + HX8357_SET_RGB, 0x02, +}; + +static u8 hx8357_seq_display_mode[] = { + HX8357_SET_DISPLAY_MODE, + HX8357_SET_DISPLAY_MODE_RGB_THROUGH | + HX8357_SET_DISPLAY_MODE_RGB_INTERFACE, +}; + +static u8 hx8369_seq_write_CABC_min_brightness[] = { + HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00, +}; + +static u8 hx8369_seq_write_CABC_control[] = { + HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24, +}; + +static u8 hx8369_seq_set_display_brightness[] = { + HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF, +}; + +static u8 hx8369_seq_write_CABC_control_setting[] = { + HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02, +}; + +static u8 hx8369_seq_extension_command[] = { + HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69, +}; + +static u8 hx8369_seq_display_related[] = { + HX8369_SET_DISPLAY_MODE, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x01, +}; + +static u8 hx8369_seq_panel_waveform_cycle[] = { + HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02, +}; + +static u8 hx8369_seq_set_address_mode[] = { + HX8357_SET_ADDRESS_MODE, 0x00, +}; + +static u8 hx8369_seq_vcom[] = { + HX8369_SET_VCOM, 0x3e, 0x3e, +}; + +static u8 hx8369_seq_gip[] = { + HX8369_SET_GIP, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70, + 0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71, + 0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04, +}; + +static u8 hx8369_seq_power[] = { + HX8369_SET_POWER, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32, + 0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, +}; + +static u8 hx8369_seq_gamma_curve_related[] = { + HX8369_SET_GAMMA_CURVE_RELATED, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, + 0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e, + 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f, + 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e, +}; + +static int hx8357_spi_write_then_read(struct lcd_device *lcdev, + u8 *txbuf, u16 txlen, + u8 *rxbuf, u16 rxlen) +{ + struct hx8357_data *lcd = lcd_get_data(lcdev); + struct spi_message msg; + struct spi_transfer xfer[2]; + u16 *local_txbuf = NULL; + int ret = 0; + + memset(xfer, 0, sizeof(xfer)); + spi_message_init(&msg); + + if (txlen) { + int i; + + local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL); + + if (!local_txbuf) + return -ENOMEM; + + for (i = 0; i < txlen; i++) { + local_txbuf[i] = txbuf[i]; + if (i > 0) + local_txbuf[i] |= 1 << 8; + } + + xfer[0].len = 2 * txlen; + xfer[0].bits_per_word = 9; + xfer[0].tx_buf = local_txbuf; + spi_message_add_tail(&xfer[0], &msg); + } + + if (rxlen) { + xfer[1].len = rxlen; + xfer[1].bits_per_word = 8; + xfer[1].rx_buf = rxbuf; + spi_message_add_tail(&xfer[1], &msg); + } + + ret = spi_sync(lcd->spi, &msg); + if (ret < 0) + dev_err(&lcdev->dev, "Couldn't send SPI data\n"); + + if (txlen) + kfree(local_txbuf); + + return ret; +} + +static inline int hx8357_spi_write_array(struct lcd_device *lcdev, + u8 *value, u8 len) +{ + return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0); +} + +static inline int hx8357_spi_write_byte(struct lcd_device *lcdev, + u8 value) +{ + return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0); +} + +static int hx8357_enter_standby(struct lcd_device *lcdev) +{ + int ret; + + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF); + if (ret < 0) + return ret; + + usleep_range(10000, 12000); + + ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE); + if (ret < 0) + return ret; + + /* + * The controller needs 120ms when entering in sleep mode before we can + * send the command to go off sleep mode + */ + msleep(120); + + return 0; +} + +static int hx8357_exit_standby(struct lcd_device *lcdev) +{ + int ret; + + ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE); + if (ret < 0) + return ret; + + /* + * The controller needs 120ms when exiting from sleep mode before we + * can send the command to enter in sleep mode + */ + msleep(120); + + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); + if (ret < 0) + return ret; + + return 0; +} + +static void hx8357_lcd_reset(struct lcd_device *lcdev) +{ + struct hx8357_data *lcd = lcd_get_data(lcdev); + + /* Reset the screen */ + gpio_set_value(lcd->reset, 1); + usleep_range(10000, 12000); + gpio_set_value(lcd->reset, 0); + usleep_range(10000, 12000); + gpio_set_value(lcd->reset, 1); + + /* The controller needs 120ms to recover from reset */ + msleep(120); +} + +static int hx8357_lcd_init(struct lcd_device *lcdev) +{ + struct hx8357_data *lcd = lcd_get_data(lcdev); + int ret; + + /* + * Set the interface selection pins to SPI mode, with three + * wires + */ + if (lcd->use_im_pins) { + gpio_set_value_cansleep(lcd->im_pins[0], 1); + gpio_set_value_cansleep(lcd->im_pins[1], 0); + gpio_set_value_cansleep(lcd->im_pins[2], 1); + } + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_power, + ARRAY_SIZE(hx8357_seq_power)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom, + ARRAY_SIZE(hx8357_seq_vcom)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal, + ARRAY_SIZE(hx8357_seq_power_normal)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving, + ARRAY_SIZE(hx8357_seq_panel_driving)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame, + ARRAY_SIZE(hx8357_seq_display_frame)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related, + ARRAY_SIZE(hx8357_seq_panel_related)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1, + ARRAY_SIZE(hx8357_seq_undefined1)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2, + ARRAY_SIZE(hx8357_seq_undefined2)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma, + ARRAY_SIZE(hx8357_seq_gamma)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode, + ARRAY_SIZE(hx8357_seq_address_mode)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format, + ARRAY_SIZE(hx8357_seq_pixel_format)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address, + ARRAY_SIZE(hx8357_seq_column_address)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address, + ARRAY_SIZE(hx8357_seq_page_address)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb, + ARRAY_SIZE(hx8357_seq_rgb)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode, + ARRAY_SIZE(hx8357_seq_display_mode)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE); + if (ret < 0) + return ret; + + /* + * The controller needs 120ms to fully recover from exiting sleep mode + */ + msleep(120); + + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); + if (ret < 0) + return ret; + + usleep_range(5000, 7000); + + ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START); + if (ret < 0) + return ret; + + return 0; +} + +static int hx8369_lcd_init(struct lcd_device *lcdev) +{ + int ret; + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_extension_command, + ARRAY_SIZE(hx8369_seq_extension_command)); + if (ret < 0) + return ret; + usleep_range(10000, 12000); + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_display_related, + ARRAY_SIZE(hx8369_seq_display_related)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_panel_waveform_cycle, + ARRAY_SIZE(hx8369_seq_panel_waveform_cycle)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_address_mode, + ARRAY_SIZE(hx8369_seq_set_address_mode)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_vcom, + ARRAY_SIZE(hx8369_seq_vcom)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_gip, + ARRAY_SIZE(hx8369_seq_gip)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_power, + ARRAY_SIZE(hx8369_seq_power)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE); + if (ret < 0) + return ret; + + /* + * The controller needs 120ms to fully recover from exiting sleep mode + */ + msleep(120); + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_gamma_curve_related, + ARRAY_SIZE(hx8369_seq_gamma_curve_related)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE); + if (ret < 0) + return ret; + usleep_range(1000, 1200); + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_write_CABC_control, + ARRAY_SIZE(hx8369_seq_write_CABC_control)); + if (ret < 0) + return ret; + usleep_range(10000, 12000); + + ret = hx8357_spi_write_array(lcdev, + hx8369_seq_write_CABC_control_setting, + ARRAY_SIZE(hx8369_seq_write_CABC_control_setting)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_array(lcdev, + hx8369_seq_write_CABC_min_brightness, + ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness)); + if (ret < 0) + return ret; + usleep_range(10000, 12000); + + ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_display_brightness, + ARRAY_SIZE(hx8369_seq_set_display_brightness)); + if (ret < 0) + return ret; + + ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); + if (ret < 0) + return ret; + + return 0; +} + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +static int hx8357_set_power(struct lcd_device *lcdev, int power) +{ + struct hx8357_data *lcd = lcd_get_data(lcdev); + int ret = 0; + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state)) + ret = hx8357_exit_standby(lcdev); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state)) + ret = hx8357_enter_standby(lcdev); + + if (ret == 0) + lcd->state = power; + else + dev_warn(&lcdev->dev, "failed to set power mode %d\n", power); + + return ret; +} + +static int hx8357_get_power(struct lcd_device *lcdev) +{ + struct hx8357_data *lcd = lcd_get_data(lcdev); + + return lcd->state; +} + +static struct lcd_ops hx8357_ops = { + .set_power = hx8357_set_power, + .get_power = hx8357_get_power, +}; + +static const struct of_device_id hx8357_dt_ids[] = { + { + .compatible = "himax,hx8357", + .data = hx8357_lcd_init, + }, + { + .compatible = "himax,hx8369", + .data = hx8369_lcd_init, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, hx8357_dt_ids); + +static int hx8357_probe(struct spi_device *spi) +{ + struct lcd_device *lcdev; + struct hx8357_data *lcd; + const struct of_device_id *match; + int i, ret; + + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "SPI setup failed.\n"); + return ret; + } + + lcd->spi = spi; + + match = of_match_device(hx8357_dt_ids, &spi->dev); + if (!match || !match->data) + return -EINVAL; + + lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0); + if (!gpio_is_valid(lcd->reset)) { + dev_err(&spi->dev, "Missing dt property: gpios-reset\n"); + return -EINVAL; + } + + ret = devm_gpio_request_one(&spi->dev, lcd->reset, + GPIOF_OUT_INIT_HIGH, + "hx8357-reset"); + if (ret) { + dev_err(&spi->dev, + "failed to request gpio %d: %d\n", + lcd->reset, ret); + return -EINVAL; + } + + if (of_find_property(spi->dev.of_node, "im-gpios", NULL)) { + lcd->use_im_pins = 1; + + for (i = 0; i < HX8357_NUM_IM_PINS; i++) { + lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node, + "im-gpios", i); + if (lcd->im_pins[i] == -EPROBE_DEFER) { + dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n"); + return -EPROBE_DEFER; + } + if (!gpio_is_valid(lcd->im_pins[i])) { + dev_err(&spi->dev, "Missing dt property: im-gpios\n"); + return -EINVAL; + } + + ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i], + GPIOF_OUT_INIT_LOW, + "im_pins"); + if (ret) { + dev_err(&spi->dev, "failed to request gpio %d: %d\n", + lcd->im_pins[i], ret); + return -EINVAL; + } + } + } else { + lcd->use_im_pins = 0; + } + + lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd, + &hx8357_ops); + if (IS_ERR(lcdev)) { + ret = PTR_ERR(lcdev); + return ret; + } + spi_set_drvdata(spi, lcdev); + + hx8357_lcd_reset(lcdev); + + ret = ((int (*)(struct lcd_device *))match->data)(lcdev); + if (ret) { + dev_err(&spi->dev, "Couldn't initialize panel\n"); + return ret; + } + + dev_info(&spi->dev, "Panel probed\n"); + + return 0; +} + +static struct spi_driver hx8357_driver = { + .probe = hx8357_probe, + .driver = { + .name = "hx8357", + .of_match_table = hx8357_dt_ids, + }, +}; + +module_spi_driver(hx8357_driver); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_DESCRIPTION("Himax HX-8357 LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c new file mode 100644 index 00000000000..ea67fe199e3 --- /dev/null +++ b/drivers/video/backlight/ili922x.c @@ -0,0 +1,550 @@ +/* + * (C) Copyright 2008 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This driver implements a lcd device for the ILITEK 922x display + * controller. The interface to the display is SPI and the display's + * memory is cyclically updated over the RGB interface. + */ + +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/lcd.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/string.h> + +/* Register offset, see manual section 8.2 */ +#define REG_START_OSCILLATION 0x00 +#define REG_DRIVER_CODE_READ 0x00 +#define REG_DRIVER_OUTPUT_CONTROL 0x01 +#define REG_LCD_AC_DRIVEING_CONTROL 0x02 +#define REG_ENTRY_MODE 0x03 +#define REG_COMPARE_1 0x04 +#define REG_COMPARE_2 0x05 +#define REG_DISPLAY_CONTROL_1 0x07 +#define REG_DISPLAY_CONTROL_2 0x08 +#define REG_DISPLAY_CONTROL_3 0x09 +#define REG_FRAME_CYCLE_CONTROL 0x0B +#define REG_EXT_INTF_CONTROL 0x0C +#define REG_POWER_CONTROL_1 0x10 +#define REG_POWER_CONTROL_2 0x11 +#define REG_POWER_CONTROL_3 0x12 +#define REG_POWER_CONTROL_4 0x13 +#define REG_RAM_ADDRESS_SET 0x21 +#define REG_WRITE_DATA_TO_GRAM 0x22 +#define REG_RAM_WRITE_MASK1 0x23 +#define REG_RAM_WRITE_MASK2 0x24 +#define REG_GAMMA_CONTROL_1 0x30 +#define REG_GAMMA_CONTROL_2 0x31 +#define REG_GAMMA_CONTROL_3 0x32 +#define REG_GAMMA_CONTROL_4 0x33 +#define REG_GAMMA_CONTROL_5 0x34 +#define REG_GAMMA_CONTROL_6 0x35 +#define REG_GAMMA_CONTROL_7 0x36 +#define REG_GAMMA_CONTROL_8 0x37 +#define REG_GAMMA_CONTROL_9 0x38 +#define REG_GAMMA_CONTROL_10 0x39 +#define REG_GATE_SCAN_CONTROL 0x40 +#define REG_VERT_SCROLL_CONTROL 0x41 +#define REG_FIRST_SCREEN_DRIVE_POS 0x42 +#define REG_SECOND_SCREEN_DRIVE_POS 0x43 +#define REG_RAM_ADDR_POS_H 0x44 +#define REG_RAM_ADDR_POS_V 0x45 +#define REG_OSCILLATOR_CONTROL 0x4F +#define REG_GPIO 0x60 +#define REG_OTP_VCM_PROGRAMMING 0x61 +#define REG_OTP_VCM_STATUS_ENABLE 0x62 +#define REG_OTP_PROGRAMMING_ID_KEY 0x65 + +/* + * maximum frequency for register access + * (not for the GRAM access) + */ +#define ILITEK_MAX_FREQ_REG 4000000 + +/* + * Device ID as found in the datasheet (supports 9221 and 9222) + */ +#define ILITEK_DEVICE_ID 0x9220 +#define ILITEK_DEVICE_ID_MASK 0xFFF0 + +/* Last two bits in the START BYTE */ +#define START_RS_INDEX 0 +#define START_RS_REG 1 +#define START_RW_WRITE 0 +#define START_RW_READ 1 + +/** + * START_BYTE(id, rs, rw) + * + * Set the start byte according to the required operation. + * The start byte is defined as: + * ---------------------------------- + * | 0 | 1 | 1 | 1 | 0 | ID | RS | RW | + * ---------------------------------- + * @id: display's id as set by the manufacturer + * @rs: operation type bit, one of: + * - START_RS_INDEX set the index register + * - START_RS_REG write/read registers/GRAM + * @rw: read/write operation + * - START_RW_WRITE write + * - START_RW_READ read + */ +#define START_BYTE(id, rs, rw) \ + (0x70 | (((id) & 0x01) << 2) | (((rs) & 0x01) << 1) | ((rw) & 0x01)) + +/** + * CHECK_FREQ_REG(spi_device s, spi_transfer x) - Check the frequency + * for the SPI transfer. According to the datasheet, the controller + * accept higher frequency for the GRAM transfer, but it requires + * lower frequency when the registers are read/written. + * The macro sets the frequency in the spi_transfer structure if + * the frequency exceeds the maximum value. + */ +#define CHECK_FREQ_REG(s, x) \ + do { \ + if (s->max_speed_hz > ILITEK_MAX_FREQ_REG) \ + ((struct spi_transfer *)x)->speed_hz = \ + ILITEK_MAX_FREQ_REG; \ + } while (0) + +#define CMD_BUFSIZE 16 + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +#define set_tx_byte(b) (tx_invert ? ~(b) : b) + +/** + * ili922x_id - id as set by manufacturer + */ +static int ili922x_id = 1; +module_param(ili922x_id, int, 0); + +static int tx_invert; +module_param(tx_invert, int, 0); + +/** + * driver's private structure + */ +struct ili922x { + struct spi_device *spi; + struct lcd_device *ld; + int power; +}; + +/** + * ili922x_read_status - read status register from display + * @spi: spi device + * @rs: output value + */ +static int ili922x_read_status(struct spi_device *spi, u16 *rs) +{ + struct spi_message msg; + struct spi_transfer xfer; + unsigned char tbuf[CMD_BUFSIZE]; + unsigned char rbuf[CMD_BUFSIZE]; + int ret, i; + + memset(&xfer, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + xfer.tx_buf = tbuf; + xfer.rx_buf = rbuf; + xfer.cs_change = 1; + CHECK_FREQ_REG(spi, &xfer); + + tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_INDEX, + START_RW_READ)); + /* + * we need 4-byte xfer here due to invalid dummy byte + * received after start byte + */ + for (i = 1; i < 4; i++) + tbuf[i] = set_tx_byte(0); /* dummy */ + + xfer.bits_per_word = 8; + xfer.len = 4; + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(spi, &msg); + if (ret < 0) { + dev_dbg(&spi->dev, "Error sending SPI message 0x%x", ret); + return ret; + } + + *rs = (rbuf[2] << 8) + rbuf[3]; + return 0; +} + +/** + * ili922x_read - read register from display + * @spi: spi device + * @reg: offset of the register to be read + * @rx: output value + */ +static int ili922x_read(struct spi_device *spi, u8 reg, u16 *rx) +{ + struct spi_message msg; + struct spi_transfer xfer_regindex, xfer_regvalue; + unsigned char tbuf[CMD_BUFSIZE]; + unsigned char rbuf[CMD_BUFSIZE]; + int ret, len = 0, send_bytes; + + memset(&xfer_regindex, 0, sizeof(struct spi_transfer)); + memset(&xfer_regvalue, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + xfer_regindex.tx_buf = tbuf; + xfer_regindex.rx_buf = rbuf; + xfer_regindex.cs_change = 1; + CHECK_FREQ_REG(spi, &xfer_regindex); + + tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_INDEX, + START_RW_WRITE)); + tbuf[1] = set_tx_byte(0); + tbuf[2] = set_tx_byte(reg); + xfer_regindex.bits_per_word = 8; + len = xfer_regindex.len = 3; + spi_message_add_tail(&xfer_regindex, &msg); + + send_bytes = len; + + tbuf[len++] = set_tx_byte(START_BYTE(ili922x_id, START_RS_REG, + START_RW_READ)); + tbuf[len++] = set_tx_byte(0); + tbuf[len] = set_tx_byte(0); + + xfer_regvalue.cs_change = 1; + xfer_regvalue.len = 3; + xfer_regvalue.tx_buf = &tbuf[send_bytes]; + xfer_regvalue.rx_buf = &rbuf[send_bytes]; + CHECK_FREQ_REG(spi, &xfer_regvalue); + + spi_message_add_tail(&xfer_regvalue, &msg); + ret = spi_sync(spi, &msg); + if (ret < 0) { + dev_dbg(&spi->dev, "Error sending SPI message 0x%x", ret); + return ret; + } + + *rx = (rbuf[1 + send_bytes] << 8) + rbuf[2 + send_bytes]; + return 0; +} + +/** + * ili922x_write - write a controller register + * @spi: struct spi_device * + * @reg: offset of the register to be written + * @value: value to be written + */ +static int ili922x_write(struct spi_device *spi, u8 reg, u16 value) +{ + struct spi_message msg; + struct spi_transfer xfer_regindex, xfer_regvalue; + unsigned char tbuf[CMD_BUFSIZE]; + unsigned char rbuf[CMD_BUFSIZE]; + int ret, len = 0; + + memset(&xfer_regindex, 0, sizeof(struct spi_transfer)); + memset(&xfer_regvalue, 0, sizeof(struct spi_transfer)); + + spi_message_init(&msg); + xfer_regindex.tx_buf = tbuf; + xfer_regindex.rx_buf = rbuf; + xfer_regindex.cs_change = 1; + CHECK_FREQ_REG(spi, &xfer_regindex); + + tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_INDEX, + START_RW_WRITE)); + tbuf[1] = set_tx_byte(0); + tbuf[2] = set_tx_byte(reg); + xfer_regindex.bits_per_word = 8; + xfer_regindex.len = 3; + spi_message_add_tail(&xfer_regindex, &msg); + + ret = spi_sync(spi, &msg); + + spi_message_init(&msg); + len = 0; + tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_REG, + START_RW_WRITE)); + tbuf[1] = set_tx_byte((value & 0xFF00) >> 8); + tbuf[2] = set_tx_byte(value & 0x00FF); + + xfer_regvalue.cs_change = 1; + xfer_regvalue.len = 3; + xfer_regvalue.tx_buf = tbuf; + xfer_regvalue.rx_buf = rbuf; + CHECK_FREQ_REG(spi, &xfer_regvalue); + + spi_message_add_tail(&xfer_regvalue, &msg); + + ret = spi_sync(spi, &msg); + if (ret < 0) { + dev_err(&spi->dev, "Error sending SPI message 0x%x", ret); + return ret; + } + return 0; +} + +#ifdef DEBUG +/** + * ili922x_reg_dump - dump all registers + */ +static void ili922x_reg_dump(struct spi_device *spi) +{ + u8 reg; + u16 rx; + + dev_dbg(&spi->dev, "ILI922x configuration registers:\n"); + for (reg = REG_START_OSCILLATION; + reg <= REG_OTP_PROGRAMMING_ID_KEY; reg++) { + ili922x_read(spi, reg, &rx); + dev_dbg(&spi->dev, "reg @ 0x%02X: 0x%04X\n", reg, rx); + } +} +#else +static inline void ili922x_reg_dump(struct spi_device *spi) {} +#endif + +/** + * set_write_to_gram_reg - initialize the display to write the GRAM + * @spi: spi device + */ +static void set_write_to_gram_reg(struct spi_device *spi) +{ + struct spi_message msg; + struct spi_transfer xfer; + unsigned char tbuf[CMD_BUFSIZE]; + + memset(&xfer, 0, sizeof(struct spi_transfer)); + + spi_message_init(&msg); + xfer.tx_buf = tbuf; + xfer.rx_buf = NULL; + xfer.cs_change = 1; + + tbuf[0] = START_BYTE(ili922x_id, START_RS_INDEX, START_RW_WRITE); + tbuf[1] = 0; + tbuf[2] = REG_WRITE_DATA_TO_GRAM; + + xfer.bits_per_word = 8; + xfer.len = 3; + spi_message_add_tail(&xfer, &msg); + spi_sync(spi, &msg); +} + +/** + * ili922x_poweron - turn the display on + * @spi: spi device + * + * The sequence to turn on the display is taken from + * the datasheet and/or the example code provided by the + * manufacturer. + */ +static int ili922x_poweron(struct spi_device *spi) +{ + int ret; + + /* Power on */ + ret = ili922x_write(spi, REG_POWER_CONTROL_1, 0x0000); + usleep_range(10000, 10500); + ret += ili922x_write(spi, REG_POWER_CONTROL_2, 0x0000); + ret += ili922x_write(spi, REG_POWER_CONTROL_3, 0x0000); + msleep(40); + ret += ili922x_write(spi, REG_POWER_CONTROL_4, 0x0000); + msleep(40); + /* register 0x56 is not documented in the datasheet */ + ret += ili922x_write(spi, 0x56, 0x080F); + ret += ili922x_write(spi, REG_POWER_CONTROL_1, 0x4240); + usleep_range(10000, 10500); + ret += ili922x_write(spi, REG_POWER_CONTROL_2, 0x0000); + ret += ili922x_write(spi, REG_POWER_CONTROL_3, 0x0014); + msleep(40); + ret += ili922x_write(spi, REG_POWER_CONTROL_4, 0x1319); + msleep(40); + + return ret; +} + +/** + * ili922x_poweroff - turn the display off + * @spi: spi device + */ +static int ili922x_poweroff(struct spi_device *spi) +{ + int ret; + + /* Power off */ + ret = ili922x_write(spi, REG_POWER_CONTROL_1, 0x0000); + usleep_range(10000, 10500); + ret += ili922x_write(spi, REG_POWER_CONTROL_2, 0x0000); + ret += ili922x_write(spi, REG_POWER_CONTROL_3, 0x0000); + msleep(40); + ret += ili922x_write(spi, REG_POWER_CONTROL_4, 0x0000); + msleep(40); + + return ret; +} + +/** + * ili922x_display_init - initialize the display by setting + * the configuration registers + * @spi: spi device + */ +static void ili922x_display_init(struct spi_device *spi) +{ + ili922x_write(spi, REG_START_OSCILLATION, 1); + usleep_range(10000, 10500); + ili922x_write(spi, REG_DRIVER_OUTPUT_CONTROL, 0x691B); + ili922x_write(spi, REG_LCD_AC_DRIVEING_CONTROL, 0x0700); + ili922x_write(spi, REG_ENTRY_MODE, 0x1030); + ili922x_write(spi, REG_COMPARE_1, 0x0000); + ili922x_write(spi, REG_COMPARE_2, 0x0000); + ili922x_write(spi, REG_DISPLAY_CONTROL_1, 0x0037); + ili922x_write(spi, REG_DISPLAY_CONTROL_2, 0x0202); + ili922x_write(spi, REG_DISPLAY_CONTROL_3, 0x0000); + ili922x_write(spi, REG_FRAME_CYCLE_CONTROL, 0x0000); + + /* Set RGB interface */ + ili922x_write(spi, REG_EXT_INTF_CONTROL, 0x0110); + + ili922x_poweron(spi); + + ili922x_write(spi, REG_GAMMA_CONTROL_1, 0x0302); + ili922x_write(spi, REG_GAMMA_CONTROL_2, 0x0407); + ili922x_write(spi, REG_GAMMA_CONTROL_3, 0x0304); + ili922x_write(spi, REG_GAMMA_CONTROL_4, 0x0203); + ili922x_write(spi, REG_GAMMA_CONTROL_5, 0x0706); + ili922x_write(spi, REG_GAMMA_CONTROL_6, 0x0407); + ili922x_write(spi, REG_GAMMA_CONTROL_7, 0x0706); + ili922x_write(spi, REG_GAMMA_CONTROL_8, 0x0000); + ili922x_write(spi, REG_GAMMA_CONTROL_9, 0x0C06); + ili922x_write(spi, REG_GAMMA_CONTROL_10, 0x0F00); + ili922x_write(spi, REG_RAM_ADDRESS_SET, 0x0000); + ili922x_write(spi, REG_GATE_SCAN_CONTROL, 0x0000); + ili922x_write(spi, REG_VERT_SCROLL_CONTROL, 0x0000); + ili922x_write(spi, REG_FIRST_SCREEN_DRIVE_POS, 0xDB00); + ili922x_write(spi, REG_SECOND_SCREEN_DRIVE_POS, 0xDB00); + ili922x_write(spi, REG_RAM_ADDR_POS_H, 0xAF00); + ili922x_write(spi, REG_RAM_ADDR_POS_V, 0xDB00); + ili922x_reg_dump(spi); + set_write_to_gram_reg(spi); +} + +static int ili922x_lcd_power(struct ili922x *lcd, int power) +{ + int ret = 0; + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + ret = ili922x_poweron(lcd->spi); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + ret = ili922x_poweroff(lcd->spi); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int ili922x_set_power(struct lcd_device *ld, int power) +{ + struct ili922x *ili = lcd_get_data(ld); + + return ili922x_lcd_power(ili, power); +} + +static int ili922x_get_power(struct lcd_device *ld) +{ + struct ili922x *ili = lcd_get_data(ld); + + return ili->power; +} + +static struct lcd_ops ili922x_ops = { + .get_power = ili922x_get_power, + .set_power = ili922x_set_power, +}; + +static int ili922x_probe(struct spi_device *spi) +{ + struct ili922x *ili; + struct lcd_device *lcd; + int ret; + u16 reg = 0; + + ili = devm_kzalloc(&spi->dev, sizeof(*ili), GFP_KERNEL); + if (!ili) + return -ENOMEM; + + ili->spi = spi; + spi_set_drvdata(spi, ili); + + /* check if the device is connected */ + ret = ili922x_read(spi, REG_DRIVER_CODE_READ, ®); + if (ret || ((reg & ILITEK_DEVICE_ID_MASK) != ILITEK_DEVICE_ID)) { + dev_err(&spi->dev, + "no LCD found: Chip ID 0x%x, ret %d\n", + reg, ret); + return -ENODEV; + } else { + dev_info(&spi->dev, "ILI%x found, SPI freq %d, mode %d\n", + reg, spi->max_speed_hz, spi->mode); + } + + ret = ili922x_read_status(spi, ®); + if (ret) { + dev_err(&spi->dev, "reading RS failed...\n"); + return ret; + } else + dev_dbg(&spi->dev, "status: 0x%x\n", reg); + + ili922x_display_init(spi); + + ili->power = FB_BLANK_POWERDOWN; + + lcd = devm_lcd_device_register(&spi->dev, "ili922xlcd", &spi->dev, ili, + &ili922x_ops); + if (IS_ERR(lcd)) { + dev_err(&spi->dev, "cannot register LCD\n"); + return PTR_ERR(lcd); + } + + ili->ld = lcd; + spi_set_drvdata(spi, ili); + + ili922x_lcd_power(ili, FB_BLANK_UNBLANK); + + return 0; +} + +static int ili922x_remove(struct spi_device *spi) +{ + ili922x_poweroff(spi); + return 0; +} + +static struct spi_driver ili922x_driver = { + .driver = { + .name = "ili922x", + .owner = THIS_MODULE, + }, + .probe = ili922x_probe, + .remove = ili922x_remove, +}; + +module_spi_driver(ili922x_driver); + +MODULE_AUTHOR("Stefano Babic <sbabic@denx.de>"); +MODULE_DESCRIPTION("ILI9221/9222 LCD driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM_DESC(ili922x_id, "set controller identifier (default=1)"); +MODULE_PARM_DESC(tx_invert, "invert bytes before sending"); diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index 9327cd1b314..2cf39e6d519 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -45,7 +45,7 @@ static inline int ili9320_write_spi(struct ili9320 *ili, /* second message is the data to transfer */ data[0] = spi->id | ILI9320_SPI_DATA | ILI9320_SPI_WRITE; - data[1] = value >> 8; + data[1] = value >> 8; data[2] = value; return spi_sync(spi->dev, &spi->message); @@ -56,11 +56,10 @@ int ili9320_write(struct ili9320 *ili, unsigned int reg, unsigned int value) dev_dbg(ili->dev, "write: reg=%02x, val=%04x\n", reg, value); return ili->write(ili, reg, value); } - EXPORT_SYMBOL_GPL(ili9320_write); int ili9320_write_regs(struct ili9320 *ili, - struct ili9320_reg *values, + const struct ili9320_reg *values, int nr_values) { int index; @@ -74,7 +73,6 @@ int ili9320_write_regs(struct ili9320 *ili, return 0; } - EXPORT_SYMBOL_GPL(ili9320_write_regs); static void ili9320_reset(struct ili9320 *lcd) @@ -171,7 +169,7 @@ static struct lcd_ops ili9320_ops = { .set_power = ili9320_set_power, }; -static void __devinit ili9320_setup_spi(struct ili9320 *ili, +static void ili9320_setup_spi(struct ili9320 *ili, struct spi_device *dev) { struct ili9320_spi *spi = &ili->access.spi; @@ -197,10 +195,10 @@ static void __devinit ili9320_setup_spi(struct ili9320 *ili, spi_message_add_tail(&spi->xfer[1], &spi->message); } -int __devinit ili9320_probe_spi(struct spi_device *spi, +int ili9320_probe_spi(struct spi_device *spi, struct ili9320_client *client) { - struct ili9320_platdata *cfg = spi->dev.platform_data; + struct ili9320_platdata *cfg = dev_get_platdata(&spi->dev); struct device *dev = &spi->dev; struct ili9320 *ili; struct lcd_device *lcd; @@ -221,10 +219,8 @@ int __devinit ili9320_probe_spi(struct spi_device *spi, /* allocate and initialse our state */ ili = devm_kzalloc(&spi->dev, sizeof(struct ili9320), GFP_KERNEL); - if (ili == NULL) { - dev_err(dev, "no memory for device\n"); + if (ili == NULL) return -ENOMEM; - } ili->access.spi.id = ILI9320_SPI_IDCODE | ILI9320_SPI_ID(1); @@ -233,11 +229,12 @@ int __devinit ili9320_probe_spi(struct spi_device *spi, ili->power = FB_BLANK_POWERDOWN; ili->platdata = cfg; - dev_set_drvdata(&spi->dev, ili); + spi_set_drvdata(spi, ili); ili9320_setup_spi(ili, spi); - lcd = lcd_device_register("ili9320", dev, ili, &ili9320_ops); + lcd = devm_lcd_device_register(&spi->dev, "ili9320", dev, ili, + &ili9320_ops); if (IS_ERR(lcd)) { dev_err(dev, "failed to register lcd device\n"); return PTR_ERR(lcd); @@ -250,66 +247,47 @@ int __devinit ili9320_probe_spi(struct spi_device *spi, ret = ili9320_power(ili, FB_BLANK_UNBLANK); if (ret != 0) { dev_err(dev, "failed to set lcd power state\n"); - goto err_unregister; + return ret; } return 0; - - err_unregister: - lcd_device_unregister(lcd); - - return ret; } - EXPORT_SYMBOL_GPL(ili9320_probe_spi); int ili9320_remove(struct ili9320 *ili) { ili9320_power(ili, FB_BLANK_POWERDOWN); - - lcd_device_unregister(ili->lcd); - return 0; } - EXPORT_SYMBOL_GPL(ili9320_remove); -#ifdef CONFIG_PM -int ili9320_suspend(struct ili9320 *lcd, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +int ili9320_suspend(struct ili9320 *lcd) { int ret; - dev_dbg(lcd->dev, "%s: event %d\n", __func__, state.event); + ret = ili9320_power(lcd, FB_BLANK_POWERDOWN); - if (state.event == PM_EVENT_SUSPEND) { - ret = ili9320_power(lcd, FB_BLANK_POWERDOWN); - - if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) { - ili9320_write(lcd, ILI9320_POWER1, lcd->power1 | - ILI9320_POWER1_SLP | - ILI9320_POWER1_DSTB); - lcd->initialised = 0; - } - - return ret; + if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) { + ili9320_write(lcd, ILI9320_POWER1, lcd->power1 | + ILI9320_POWER1_SLP | + ILI9320_POWER1_DSTB); + lcd->initialised = 0; } - return 0; + return ret; } - EXPORT_SYMBOL_GPL(ili9320_suspend); int ili9320_resume(struct ili9320 *lcd) { dev_info(lcd->dev, "resuming from power state %d\n", lcd->power); - if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) { + if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) ili9320_write(lcd, ILI9320_POWER1, 0x00); - } return ili9320_power(lcd, FB_BLANK_UNBLANK); } - EXPORT_SYMBOL_GPL(ili9320_resume); #endif @@ -318,7 +296,6 @@ void ili9320_shutdown(struct ili9320 *lcd) { ili9320_power(lcd, FB_BLANK_POWERDOWN); } - EXPORT_SYMBOL_GPL(ili9320_shutdown); MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); diff --git a/drivers/video/backlight/ili9320.h b/drivers/video/backlight/ili9320.h index e388eca7cac..42329e7aa9a 100644 --- a/drivers/video/backlight/ili9320.h +++ b/drivers/video/backlight/ili9320.h @@ -63,7 +63,7 @@ extern int ili9320_write(struct ili9320 *ili, unsigned int reg, unsigned int value); extern int ili9320_write_regs(struct ili9320 *ili, - struct ili9320_reg *values, + const struct ili9320_reg *values, int nr_values); /* Device probe */ @@ -76,5 +76,5 @@ extern void ili9320_shutdown(struct ili9320 *lcd); /* PM */ -extern int ili9320_suspend(struct ili9320 *lcd, pm_message_t state); +extern int ili9320_suspend(struct ili9320 *lcd); extern int ili9320_resume(struct ili9320 *lcd); diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 16f593b6442..6ce96b4a879 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -9,8 +9,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/backlight.h> #include <linux/device.h> #include <linux/fb.h> @@ -40,15 +38,17 @@ static int jornada_bl_get_brightness(struct backlight_device *bd) ret = jornada_ssp_byte(GETBRIGHTNESS); if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) { - pr_err("get brightness timeout\n"); + dev_err(&bd->dev, "get brightness timeout\n"); jornada_ssp_end(); return -ETIMEDOUT; - } else /* exchange txdummy for value */ + } else { + /* exchange txdummy for value */ ret = jornada_ssp_byte(TXDUMMY); + } jornada_ssp_end(); - return (BL_MAX_BRIGHT - ret); + return BL_MAX_BRIGHT - ret; } static int jornada_bl_update_status(struct backlight_device *bd) @@ -61,7 +61,7 @@ static int jornada_bl_update_status(struct backlight_device *bd) if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) { ret = jornada_ssp_byte(BRIGHTNESSOFF); if (ret != TXDUMMY) { - pr_info("brightness off timeout\n"); + dev_info(&bd->dev, "brightness off timeout\n"); /* turn off backlight */ PPSR &= ~PPC_LDD1; PPDR |= PPC_LDD1; @@ -72,23 +72,28 @@ static int jornada_bl_update_status(struct backlight_device *bd) /* send command to our mcu */ if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) { - pr_info("failed to set brightness\n"); + dev_info(&bd->dev, "failed to set brightness\n"); ret = -ETIMEDOUT; goto out; } - /* at this point we expect that the mcu has accepted - our command and is waiting for our new value - please note that maximum brightness is 255, - but due to physical layout it is equal to 0, so we simply - invert the value (MAX VALUE - NEW VALUE). */ - if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) != TXDUMMY) { - pr_err("set brightness failed\n"); + /* + * at this point we expect that the mcu has accepted + * our command and is waiting for our new value + * please note that maximum brightness is 255, + * but due to physical layout it is equal to 0, so we simply + * invert the value (MAX VALUE - NEW VALUE). + */ + if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) + != TXDUMMY) { + dev_err(&bd->dev, "set brightness failed\n"); ret = -ETIMEDOUT; } - /* If infact we get an TXDUMMY as output we are happy and dont - make any further comments about it */ + /* + * If infact we get an TXDUMMY as output we are happy and dont + * make any further comments about it + */ out: jornada_ssp_end(); @@ -110,40 +115,33 @@ static int jornada_bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = BL_MAX_BRIGHT; - bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, - &jornada_bl_ops, &props); + bd = devm_backlight_device_register(&pdev->dev, S1D_DEVICENAME, + &pdev->dev, NULL, &jornada_bl_ops, + &props); if (IS_ERR(bd)) { ret = PTR_ERR(bd); - pr_err("failed to register device, err=%x\n", ret); + dev_err(&pdev->dev, "failed to register device, err=%x\n", ret); return ret; } bd->props.power = FB_BLANK_UNBLANK; bd->props.brightness = BL_DEF_BRIGHT; - /* note. make sure max brightness is set otherwise - you will get seemingly non-related errors when - trying to change brightness */ + /* + * note. make sure max brightness is set otherwise + * you will get seemingly non-related errors when + * trying to change brightness + */ jornada_bl_update_status(bd); platform_set_drvdata(pdev, bd); - pr_info("HP Jornada 700 series backlight driver\n"); - - return 0; -} - -static int jornada_bl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - - backlight_device_unregister(bd); + dev_info(&pdev->dev, "HP Jornada 700 series backlight driver\n"); return 0; } static struct platform_driver jornada_bl_driver = { .probe = jornada_bl_probe, - .remove = jornada_bl_remove, .driver = { .name = "jornada_bl", }, diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c index 635b30523fd..da3876c9b3a 100644 --- a/drivers/video/backlight/jornada720_lcd.c +++ b/drivers/video/backlight/jornada720_lcd.c @@ -9,8 +9,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/device.h> #include <linux/fb.h> #include <linux/kernel.h> @@ -27,7 +25,7 @@ #define LCD_MAX_CONTRAST 0xff #define LCD_DEF_CONTRAST 0x80 -static int jornada_lcd_get_power(struct lcd_device *dev) +static int jornada_lcd_get_power(struct lcd_device *ld) { /* LDD2 in PPC = LCD POWER */ if (PPSR & PPC_LDD2) @@ -36,17 +34,17 @@ static int jornada_lcd_get_power(struct lcd_device *dev) return FB_BLANK_POWERDOWN; /* PW OFF */ } -static int jornada_lcd_get_contrast(struct lcd_device *dev) +static int jornada_lcd_get_contrast(struct lcd_device *ld) { int ret; - if (jornada_lcd_get_power(dev) != FB_BLANK_UNBLANK) + if (jornada_lcd_get_power(ld) != FB_BLANK_UNBLANK) return 0; jornada_ssp_start(); if (jornada_ssp_byte(GETCONTRAST) != TXDUMMY) { - pr_err("get contrast failed\n"); + dev_err(&ld->dev, "get contrast failed\n"); jornada_ssp_end(); return -ETIMEDOUT; } else { @@ -56,7 +54,7 @@ static int jornada_lcd_get_contrast(struct lcd_device *dev) } } -static int jornada_lcd_set_contrast(struct lcd_device *dev, int value) +static int jornada_lcd_set_contrast(struct lcd_device *ld, int value) { int ret; @@ -67,7 +65,7 @@ static int jornada_lcd_set_contrast(struct lcd_device *dev, int value) /* push the new value */ if (jornada_ssp_byte(value) != TXDUMMY) { - pr_err("set contrast failed\n"); + dev_err(&ld->dev, "set contrast failed\n"); jornada_ssp_end(); return -ETIMEDOUT; } @@ -78,13 +76,14 @@ static int jornada_lcd_set_contrast(struct lcd_device *dev, int value) return 0; } -static int jornada_lcd_set_power(struct lcd_device *dev, int power) +static int jornada_lcd_set_power(struct lcd_device *ld, int power) { if (power != FB_BLANK_UNBLANK) { PPSR &= ~PPC_LDD2; PPDR |= PPC_LDD2; - } else + } else { PPSR |= PPC_LDD2; + } return 0; } @@ -101,11 +100,12 @@ static int jornada_lcd_probe(struct platform_device *pdev) struct lcd_device *lcd_device; int ret; - lcd_device = lcd_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_lcd_props); + lcd_device = devm_lcd_device_register(&pdev->dev, S1D_DEVICENAME, + &pdev->dev, NULL, &jornada_lcd_props); if (IS_ERR(lcd_device)) { ret = PTR_ERR(lcd_device); - pr_err("failed to register device\n"); + dev_err(&pdev->dev, "failed to register device\n"); return ret; } @@ -120,18 +120,8 @@ static int jornada_lcd_probe(struct platform_device *pdev) return 0; } -static int jornada_lcd_remove(struct platform_device *pdev) -{ - struct lcd_device *lcd_device = platform_get_drvdata(pdev); - - lcd_device_unregister(lcd_device); - - return 0; -} - static struct platform_driver jornada_lcd_driver = { .probe = jornada_lcd_probe, - .remove = jornada_lcd_remove, .driver = { .name = "jornada_lcd", }, diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index 72dd5556a35..84a110a719c 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -34,9 +34,9 @@ static void kb3886_bl_set_intensity(int intensity) mutex_lock(&bl_mutex); intensity = intensity&0xff; outb(KB3886_ADC_DAC_PWM, KB3886_PARENT); - msleep(10); + usleep_range(10000, 11000); outb(KB3886_PWM0_WRITE, KB3886_IO); - msleep(10); + usleep_range(10000, 11000); outb(intensity, KB3886_IO); mutex_unlock(&bl_mutex); } @@ -78,7 +78,7 @@ static struct kb3886bl_machinfo *bl_machinfo; static unsigned long kb3886bl_flags; #define KB3886BL_SUSPENDED 0x01 -static struct dmi_system_id __initdata kb3886bl_device_table[] = { +static struct dmi_system_id kb3886bl_device_table[] __initdata = { { .ident = "Sahara Touch-iT", .matches = { @@ -106,29 +106,28 @@ static int kb3886bl_send_intensity(struct backlight_device *bd) return 0; } -#ifdef CONFIG_PM -static int kb3886bl_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int kb3886bl_suspend(struct device *dev) { - struct backlight_device *bd = platform_get_drvdata(pdev); + struct backlight_device *bd = dev_get_drvdata(dev); kb3886bl_flags |= KB3886BL_SUSPENDED; backlight_update_status(bd); return 0; } -static int kb3886bl_resume(struct platform_device *pdev) +static int kb3886bl_resume(struct device *dev) { - struct backlight_device *bd = platform_get_drvdata(pdev); + struct backlight_device *bd = dev_get_drvdata(dev); kb3886bl_flags &= ~KB3886BL_SUSPENDED; backlight_update_status(bd); return 0; } -#else -#define kb3886bl_suspend NULL -#define kb3886bl_resume NULL #endif +static SIMPLE_DEV_PM_OPS(kb3886bl_pm_ops, kb3886bl_suspend, kb3886bl_resume); + static int kb3886bl_get_intensity(struct backlight_device *bd) { return kb3886bl_intensity; @@ -142,7 +141,7 @@ static const struct backlight_ops kb3886bl_ops = { static int kb3886bl_probe(struct platform_device *pdev) { struct backlight_properties props; - struct kb3886bl_machinfo *machinfo = pdev->dev.platform_data; + struct kb3886bl_machinfo *machinfo = dev_get_platdata(&pdev->dev); bl_machinfo = machinfo; if (!machinfo->limit_mask) @@ -151,10 +150,10 @@ static int kb3886bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; - kb3886_backlight_device = backlight_device_register("kb3886-bl", - &pdev->dev, NULL, - &kb3886bl_ops, - &props); + kb3886_backlight_device = devm_backlight_device_register(&pdev->dev, + "kb3886-bl", &pdev->dev, + NULL, &kb3886bl_ops, + &props); if (IS_ERR(kb3886_backlight_device)) return PTR_ERR(kb3886_backlight_device); @@ -167,22 +166,11 @@ static int kb3886bl_probe(struct platform_device *pdev) return 0; } -static int kb3886bl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - - backlight_device_unregister(bd); - - return 0; -} - static struct platform_driver kb3886bl_driver = { .probe = kb3886bl_probe, - .remove = kb3886bl_remove, - .suspend = kb3886bl_suspend, - .resume = kb3886bl_resume, .driver = { .name = "kb3886-bl", + .pm = &kb3886bl_pm_ops, }, }; diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 40f606a8609..5fa2649c963 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -4,7 +4,7 @@ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. * * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> - * Inspired by Marek Vasut work in l4f00242t03.c + * Inspired by Marek Vasut work in l4f00242t03.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -33,7 +33,6 @@ struct l4f00242t03_priv { struct regulator *core_reg; }; - static void l4f00242t03_reset(unsigned int gpio) { pr_debug("l4f00242t03_reset.\n"); @@ -49,17 +48,36 @@ static void l4f00242t03_reset(unsigned int gpio) static void l4f00242t03_lcd_init(struct spi_device *spi) { - struct l4f00242t03_pdata *pdata = spi->dev.platform_data; - struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) }; + int ret; dev_dbg(&spi->dev, "initializing LCD\n"); - regulator_set_voltage(priv->io_reg, 1800000, 1800000); - regulator_enable(priv->io_reg); + ret = regulator_set_voltage(priv->io_reg, 1800000, 1800000); + if (ret) { + dev_err(&spi->dev, "failed to set the IO regulator voltage.\n"); + return; + } + ret = regulator_enable(priv->io_reg); + if (ret) { + dev_err(&spi->dev, "failed to enable the IO regulator.\n"); + return; + } - regulator_set_voltage(priv->core_reg, 2800000, 2800000); - regulator_enable(priv->core_reg); + ret = regulator_set_voltage(priv->core_reg, 2800000, 2800000); + if (ret) { + dev_err(&spi->dev, "failed to set the core regulator voltage.\n"); + regulator_disable(priv->io_reg); + return; + } + ret = regulator_enable(priv->core_reg); + if (ret) { + dev_err(&spi->dev, "failed to enable the core regulator.\n"); + regulator_disable(priv->io_reg); + return; + } l4f00242t03_reset(pdata->reset_gpio); @@ -70,8 +88,8 @@ static void l4f00242t03_lcd_init(struct spi_device *spi) static void l4f00242t03_lcd_powerdown(struct spi_device *spi) { - struct l4f00242t03_pdata *pdata = spi->dev.platform_data; - struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); dev_dbg(&spi->dev, "Powering down LCD\n"); @@ -150,10 +168,10 @@ static struct lcd_ops l4f_ops = { .get_power = l4f00242t03_lcd_power_get, }; -static int __devinit l4f00242t03_probe(struct spi_device *spi) +static int l4f00242t03_probe(struct spi_device *spi) { struct l4f00242t03_priv *priv; - struct l4f00242t03_pdata *pdata = spi->dev.platform_data; + struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); int ret; if (pdata == NULL) { @@ -163,56 +181,49 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) priv = devm_kzalloc(&spi->dev, sizeof(struct l4f00242t03_priv), GFP_KERNEL); - - if (priv == NULL) { - dev_err(&spi->dev, "No memory for this device.\n"); + if (priv == NULL) return -ENOMEM; - } - dev_set_drvdata(&spi->dev, priv); + spi_set_drvdata(spi, priv); spi->bits_per_word = 9; spi_setup(spi); priv->spi = spi; - ret = gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH, - "lcd l4f00242t03 reset"); + ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio, + GPIOF_OUT_INIT_HIGH, "lcd l4f00242t03 reset"); if (ret) { dev_err(&spi->dev, "Unable to get the lcd l4f00242t03 reset gpio.\n"); return ret; } - ret = gpio_request_one(pdata->data_enable_gpio, GPIOF_OUT_INIT_LOW, - "lcd l4f00242t03 data enable"); + ret = devm_gpio_request_one(&spi->dev, pdata->data_enable_gpio, + GPIOF_OUT_INIT_LOW, "lcd l4f00242t03 data enable"); if (ret) { dev_err(&spi->dev, "Unable to get the lcd l4f00242t03 data en gpio.\n"); - goto err; + return ret; } - priv->io_reg = regulator_get(&spi->dev, "vdd"); + priv->io_reg = devm_regulator_get(&spi->dev, "vdd"); if (IS_ERR(priv->io_reg)) { - ret = PTR_ERR(priv->io_reg); dev_err(&spi->dev, "%s: Unable to get the IO regulator\n", __func__); - goto err2; + return PTR_ERR(priv->io_reg); } - priv->core_reg = regulator_get(&spi->dev, "vcore"); + priv->core_reg = devm_regulator_get(&spi->dev, "vcore"); if (IS_ERR(priv->core_reg)) { - ret = PTR_ERR(priv->core_reg); dev_err(&spi->dev, "%s: Unable to get the core regulator\n", __func__); - goto err3; + return PTR_ERR(priv->core_reg); } - priv->ld = lcd_device_register("l4f00242t03", - &spi->dev, priv, &l4f_ops); - if (IS_ERR(priv->ld)) { - ret = PTR_ERR(priv->ld); - goto err4; - } + priv->ld = devm_lcd_device_register(&spi->dev, "l4f00242t03", &spi->dev, + priv, &l4f_ops); + if (IS_ERR(priv->ld)) + return PTR_ERR(priv->ld); /* Init the LCD */ l4f00242t03_lcd_init(spi); @@ -222,41 +233,19 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n"); return 0; - -err4: - regulator_put(priv->core_reg); -err3: - regulator_put(priv->io_reg); -err2: - gpio_free(pdata->data_enable_gpio); -err: - gpio_free(pdata->reset_gpio); - - return ret; } -static int __devexit l4f00242t03_remove(struct spi_device *spi) +static int l4f00242t03_remove(struct spi_device *spi) { - struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); - struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data; + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); - lcd_device_unregister(priv->ld); - - dev_set_drvdata(&spi->dev, NULL); - - gpio_free(pdata->data_enable_gpio); - gpio_free(pdata->reset_gpio); - - regulator_put(priv->io_reg); - regulator_put(priv->core_reg); - return 0; } static void l4f00242t03_shutdown(struct spi_device *spi) { - struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + struct l4f00242t03_priv *priv = spi_get_drvdata(spi); if (priv) l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); @@ -269,7 +258,7 @@ static struct spi_driver l4f00242t03_driver = { .owner = THIS_MODULE, }, .probe = l4f00242t03_probe, - .remove = __devexit_p(l4f00242t03_remove), + .remove = l4f00242t03_remove, .shutdown = l4f00242t03_shutdown, }; diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index a5d0d024bb9..7de847df224 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -89,7 +89,7 @@ static inline void lcd_unregister_fb(struct lcd_device *ld) } #endif /* CONFIG_FB */ -static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr, +static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc; @@ -105,10 +105,10 @@ static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr, return rc; } -static ssize_t lcd_store_power(struct device *dev, +static ssize_t lcd_power_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int rc = -ENXIO; + int rc; struct lcd_device *ld = to_lcd_device(dev); unsigned long power; @@ -116,6 +116,8 @@ static ssize_t lcd_store_power(struct device *dev, if (rc) return rc; + rc = -ENXIO; + mutex_lock(&ld->ops_lock); if (ld->ops && ld->ops->set_power) { pr_debug("set power to %lu\n", power); @@ -126,8 +128,9 @@ static ssize_t lcd_store_power(struct device *dev, return rc; } +static DEVICE_ATTR_RW(lcd_power); -static ssize_t lcd_show_contrast(struct device *dev, +static ssize_t contrast_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc = -ENXIO; @@ -141,10 +144,10 @@ static ssize_t lcd_show_contrast(struct device *dev, return rc; } -static ssize_t lcd_store_contrast(struct device *dev, +static ssize_t contrast_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int rc = -ENXIO; + int rc; struct lcd_device *ld = to_lcd_device(dev); unsigned long contrast; @@ -152,6 +155,8 @@ static ssize_t lcd_store_contrast(struct device *dev, if (rc) return rc; + rc = -ENXIO; + mutex_lock(&ld->ops_lock); if (ld->ops && ld->ops->set_contrast) { pr_debug("set contrast to %lu\n", contrast); @@ -162,14 +167,16 @@ static ssize_t lcd_store_contrast(struct device *dev, return rc; } +static DEVICE_ATTR_RW(contrast); -static ssize_t lcd_show_max_contrast(struct device *dev, +static ssize_t max_contrast_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lcd_device *ld = to_lcd_device(dev); return sprintf(buf, "%d\n", ld->props.max_contrast); } +static DEVICE_ATTR_RO(max_contrast); static struct class *lcd_class; @@ -179,12 +186,13 @@ static void lcd_device_release(struct device *dev) kfree(ld); } -static struct device_attribute lcd_device_attributes[] = { - __ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power), - __ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast), - __ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL), - __ATTR_NULL, +static struct attribute *lcd_device_attrs[] = { + &dev_attr_lcd_power.attr, + &dev_attr_contrast.attr, + &dev_attr_max_contrast.attr, + NULL, }; +ATTRIBUTE_GROUPS(lcd_device); /** * lcd_device_register - register a new object of lcd_device class. @@ -215,12 +223,12 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent, new_ld->dev.class = lcd_class; new_ld->dev.parent = parent; new_ld->dev.release = lcd_device_release; - dev_set_name(&new_ld->dev, name); + dev_set_name(&new_ld->dev, "%s", name); dev_set_drvdata(&new_ld->dev, devdata); rc = device_register(&new_ld->dev); if (rc) { - kfree(new_ld); + put_device(&new_ld->dev); return ERR_PTR(rc); } @@ -256,6 +264,76 @@ void lcd_device_unregister(struct lcd_device *ld) } EXPORT_SYMBOL(lcd_device_unregister); +static void devm_lcd_device_release(struct device *dev, void *res) +{ + struct lcd_device *lcd = *(struct lcd_device **)res; + + lcd_device_unregister(lcd); +} + +static int devm_lcd_device_match(struct device *dev, void *res, void *data) +{ + struct lcd_device **r = res; + + return *r == data; +} + +/** + * devm_lcd_device_register - resource managed lcd_device_register() + * @dev: the device to register + * @name: the name of the device + * @parent: a pointer to the parent device + * @devdata: an optional pointer to be stored for private driver use + * @ops: the lcd operations structure + * + * @return a struct lcd on success, or an ERR_PTR on error + * + * Managed lcd_device_register(). The lcd_device returned from this function + * are automatically freed on driver detach. See lcd_device_register() + * for more information. + */ +struct lcd_device *devm_lcd_device_register(struct device *dev, + const char *name, struct device *parent, + void *devdata, struct lcd_ops *ops) +{ + struct lcd_device **ptr, *lcd; + + ptr = devres_alloc(devm_lcd_device_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + lcd = lcd_device_register(name, parent, devdata, ops); + if (!IS_ERR(lcd)) { + *ptr = lcd; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return lcd; +} +EXPORT_SYMBOL(devm_lcd_device_register); + +/** + * devm_lcd_device_unregister - resource managed lcd_device_unregister() + * @dev: the device to unregister + * @ld: the lcd device to unregister + * + * Deallocated a lcd allocated with devm_lcd_device_register(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_lcd_device_unregister(struct device *dev, struct lcd_device *ld) +{ + int rc; + + rc = devres_release(dev, devm_lcd_device_release, + devm_lcd_device_match, ld); + WARN_ON(rc); +} +EXPORT_SYMBOL(devm_lcd_device_unregister); + + static void __exit lcd_class_exit(void) { class_destroy(lcd_class); @@ -270,7 +348,7 @@ static int __init lcd_class_init(void) return PTR_ERR(lcd_class); } - lcd_class->dev_attrs = lcd_device_attributes; + lcd_class->dev_groups = lcd_device_groups; return 0; } diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 58f517fb7d4..506a6c23603 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -9,29 +9,20 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <linux/wait.h> -#include <linux/fb.h> +#include <linux/backlight.h> #include <linux/delay.h> +#include <linux/fb.h> #include <linux/gpio.h> -#include <linux/spi/spi.h> -#include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/lcd.h> -#include <linux/backlight.h> #include <linux/module.h> #include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/wait.h> #include "ld9040_gamma.h" @@ -43,7 +34,6 @@ #define MIN_BRIGHTNESS 0 #define MAX_BRIGHTNESS 24 -#define power_is_on(pwr) ((pwr) <= FB_BLANK_NORMAL) struct ld9040 { struct device *dev; @@ -78,7 +68,7 @@ static void ld9040_regulator_enable(struct ld9040 *lcd) lcd->enabled = true; } - mdelay(pd->power_on_delay); + msleep(pd->power_on_delay); out: mutex_unlock(&lcd->lock); } @@ -474,8 +464,9 @@ static int ld9040_panel_send_sequence(struct ld9040 *lcd, ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]); if (ret) break; - } else - udelay(wbuf[i+1]*1000); + } else { + msleep(wbuf[i+1]); + } i += 2; } @@ -513,14 +504,9 @@ gamma_err: static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma) { - int ret = 0; - - ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); - - return ret; + return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); } - static int ld9040_ldi_init(struct ld9040 *lcd) { int ret, i; @@ -539,7 +525,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd) for (i = 0; i < ARRAY_SIZE(init_seq); i++) { ret = ld9040_panel_send_sequence(lcd, init_seq[i]); /* workaround: minimum delay time for transferring CMD */ - udelay(300); + usleep_range(300, 310); if (ret) break; } @@ -549,11 +535,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd) static int ld9040_ldi_enable(struct ld9040 *lcd) { - int ret = 0; - - ret = ld9040_panel_send_sequence(lcd, seq_display_on); - - return ret; + return ld9040_panel_send_sequence(lcd, seq_display_on); } static int ld9040_ldi_disable(struct ld9040 *lcd) @@ -566,25 +548,27 @@ static int ld9040_ldi_disable(struct ld9040 *lcd) return ret; } +static int ld9040_power_is_on(int power) +{ + return power <= FB_BLANK_NORMAL; +} + static int ld9040_power_on(struct ld9040 *lcd) { int ret = 0; - struct lcd_platform_data *pd = NULL; + struct lcd_platform_data *pd; + pd = lcd->lcd_pd; - if (!pd) { - dev_err(lcd->dev, "platform data is NULL.\n"); - return -EFAULT; - } /* lcd power on */ ld9040_regulator_enable(lcd); if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); - return -EFAULT; + return -EINVAL; } else { pd->reset(lcd->ld); - mdelay(pd->reset_delay); + msleep(pd->reset_delay); } ret = ld9040_ldi_init(lcd); @@ -604,14 +588,10 @@ static int ld9040_power_on(struct ld9040 *lcd) static int ld9040_power_off(struct ld9040 *lcd) { - int ret = 0; - struct lcd_platform_data *pd = NULL; + int ret; + struct lcd_platform_data *pd; pd = lcd->lcd_pd; - if (!pd) { - dev_err(lcd->dev, "platform data is NULL.\n"); - return -EFAULT; - } ret = ld9040_ldi_disable(lcd); if (ret) { @@ -619,7 +599,7 @@ static int ld9040_power_off(struct ld9040 *lcd) return -EIO; } - mdelay(pd->power_off_delay); + msleep(pd->power_off_delay); /* lcd power off */ ld9040_regulator_disable(lcd); @@ -631,9 +611,9 @@ static int ld9040_power(struct ld9040 *lcd, int power) { int ret = 0; - if (power_is_on(power) && !power_is_on(lcd->power)) + if (ld9040_power_is_on(power) && !ld9040_power_is_on(lcd->power)) ret = ld9040_power_on(lcd); - else if (!power_is_on(power) && power_is_on(lcd->power)) + else if (!ld9040_power_is_on(power) && ld9040_power_is_on(lcd->power)) ret = ld9040_power_off(lcd); if (!ret) @@ -698,7 +678,6 @@ static const struct backlight_ops ld9040_backlight_ops = { .update_status = ld9040_set_brightness, }; - static int ld9040_probe(struct spi_device *spi) { int ret = 0; @@ -723,25 +702,24 @@ static int ld9040_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL.\n"); - return -EFAULT; + return -EINVAL; } mutex_init(&lcd->lock); - ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); + ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); if (ret) { dev_err(lcd->dev, "Failed to get regulators: %d\n", ret); return ret; } - ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops); - if (IS_ERR(ld)) { - ret = PTR_ERR(ld); - goto out_free_regulator; - } + ld = devm_lcd_device_register(&spi->dev, "ld9040", &spi->dev, lcd, + &ld9040_lcd_ops); + if (IS_ERR(ld)) + return PTR_ERR(ld); lcd->ld = ld; @@ -749,12 +727,10 @@ static int ld9040_probe(struct spi_device *spi) props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bd = backlight_device_register("ld9040-bl", &spi->dev, - lcd, &ld9040_backlight_ops, &props); - if (IS_ERR(bd)) { - ret = PTR_ERR(bd); - goto out_unregister_lcd; - } + bd = devm_backlight_device_register(&spi->dev, "ld9040-bl", &spi->dev, + lcd, &ld9040_backlight_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); bd->props.brightness = MAX_BRIGHTNESS; lcd->bd = bd; @@ -772,71 +748,54 @@ static int ld9040_probe(struct spi_device *spi) lcd->power = FB_BLANK_POWERDOWN; ld9040_power(lcd, FB_BLANK_UNBLANK); - } else + } else { lcd->power = FB_BLANK_UNBLANK; + } - dev_set_drvdata(&spi->dev, lcd); + spi_set_drvdata(spi, lcd); dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); return 0; - -out_unregister_lcd: - lcd_device_unregister(lcd->ld); -out_free_regulator: - regulator_bulk_free(ARRAY_SIZE(supplies), supplies); - - return ret; } -static int __devexit ld9040_remove(struct spi_device *spi) +static int ld9040_remove(struct spi_device *spi) { - struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + struct ld9040 *lcd = spi_get_drvdata(spi); ld9040_power(lcd, FB_BLANK_POWERDOWN); - backlight_device_unregister(lcd->bd); - lcd_device_unregister(lcd->ld); - regulator_bulk_free(ARRAY_SIZE(supplies), supplies); - return 0; } -#if defined(CONFIG_PM) -static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int ld9040_suspend(struct device *dev) { - int ret = 0; - struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + struct ld9040 *lcd = dev_get_drvdata(dev); - dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + dev_dbg(dev, "lcd->power = %d\n", lcd->power); /* * when lcd panel is suspend, lcd panel becomes off * regardless of status. */ - ret = ld9040_power(lcd, FB_BLANK_POWERDOWN); - - return ret; + return ld9040_power(lcd, FB_BLANK_POWERDOWN); } -static int ld9040_resume(struct spi_device *spi) +static int ld9040_resume(struct device *dev) { - int ret = 0; - struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + struct ld9040 *lcd = dev_get_drvdata(dev); lcd->power = FB_BLANK_POWERDOWN; - ret = ld9040_power(lcd, FB_BLANK_UNBLANK); - - return ret; + return ld9040_power(lcd, FB_BLANK_UNBLANK); } -#else -#define ld9040_suspend NULL -#define ld9040_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume); + /* Power down all displays on reboot, poweroff or halt. */ static void ld9040_shutdown(struct spi_device *spi) { - struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + struct ld9040 *lcd = spi_get_drvdata(spi); ld9040_power(lcd, FB_BLANK_POWERDOWN); } @@ -845,12 +804,11 @@ static struct spi_driver ld9040_driver = { .driver = { .name = "ld9040", .owner = THIS_MODULE, + .pm = &ld9040_pm_ops, }, .probe = ld9040_probe, - .remove = __devexit_p(ld9040_remove), + .remove = ld9040_remove, .shutdown = ld9040_shutdown, - .suspend = ld9040_suspend, - .resume = ld9040_resume, }; module_spi_driver(ld9040_driver); diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h index 038d9c86ec0..c5e586d9738 100644 --- a/drivers/video/backlight/ld9040_gamma.h +++ b/drivers/video/backlight/ld9040_gamma.h @@ -169,7 +169,9 @@ static const unsigned int ld9040_22_50[] = { struct ld9040_gamma { unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; -} gamma_table = { +}; + +static struct ld9040_gamma gamma_table = { .gamma_22_table[0] = (unsigned int *)&ld9040_22_50, .gamma_22_table[1] = (unsigned int *)&ld9040_22_70, .gamma_22_table[2] = (unsigned int *)&ld9040_22_80, diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index bebeb63607d..cff1fbe89a1 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -257,7 +257,7 @@ static struct attribute_group lm3533_bl_attribute_group = { .attrs = lm3533_bl_attributes }; -static int __devinit lm3533_bl_setup(struct lm3533_bl *bl, +static int lm3533_bl_setup(struct lm3533_bl *bl, struct lm3533_bl_platform_data *pdata) { int ret; @@ -269,7 +269,7 @@ static int __devinit lm3533_bl_setup(struct lm3533_bl *bl, return lm3533_ctrlbank_set_pwm(&bl->cb, pdata->pwm); } -static int __devinit lm3533_bl_probe(struct platform_device *pdev) +static int lm3533_bl_probe(struct platform_device *pdev) { struct lm3533 *lm3533; struct lm3533_bl_platform_data *pdata; @@ -284,7 +284,7 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev) if (!lm3533) return -EINVAL; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "no platform data\n"); return -EINVAL; @@ -295,12 +295,9 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev) return -EINVAL; } - bl = kzalloc(sizeof(*bl), GFP_KERNEL); - if (!bl) { - dev_err(&pdev->dev, - "failed to allocate memory for backlight\n"); + bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL); + if (!bl) return -ENOMEM; - } bl->lm3533 = lm3533; bl->id = pdev->id; @@ -313,12 +310,12 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev) props.type = BACKLIGHT_RAW; props.max_brightness = LM3533_BL_MAX_BRIGHTNESS; props.brightness = pdata->default_brightness; - bd = backlight_device_register(pdata->name, pdev->dev.parent, bl, - &lm3533_bl_ops, &props); + bd = devm_backlight_device_register(&pdev->dev, pdata->name, + pdev->dev.parent, bl, &lm3533_bl_ops, + &props); if (IS_ERR(bd)) { dev_err(&pdev->dev, "failed to register backlight device\n"); - ret = PTR_ERR(bd); - goto err_free; + return PTR_ERR(bd); } bl->bd = bd; @@ -329,7 +326,7 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev) ret = sysfs_create_group(&bd->dev.kobj, &lm3533_bl_attribute_group); if (ret < 0) { dev_err(&pdev->dev, "failed to create sysfs attributes\n"); - goto err_unregister; + return ret; } backlight_update_status(bd); @@ -346,15 +343,11 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev) err_sysfs_remove: sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); -err_unregister: - backlight_device_unregister(bd); -err_free: - kfree(bl); return ret; } -static int __devexit lm3533_bl_remove(struct platform_device *pdev) +static int lm3533_bl_remove(struct platform_device *pdev) { struct lm3533_bl *bl = platform_get_drvdata(pdev); struct backlight_device *bd = bl->bd; @@ -366,35 +359,32 @@ static int __devexit lm3533_bl_remove(struct platform_device *pdev) lm3533_ctrlbank_disable(&bl->cb); sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); - backlight_device_unregister(bd); - kfree(bl); return 0; } -#ifdef CONFIG_PM -static int lm3533_bl_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int lm3533_bl_suspend(struct device *dev) { - struct lm3533_bl *bl = platform_get_drvdata(pdev); + struct lm3533_bl *bl = dev_get_drvdata(dev); - dev_dbg(&pdev->dev, "%s\n", __func__); + dev_dbg(dev, "%s\n", __func__); return lm3533_ctrlbank_disable(&bl->cb); } -static int lm3533_bl_resume(struct platform_device *pdev) +static int lm3533_bl_resume(struct device *dev) { - struct lm3533_bl *bl = platform_get_drvdata(pdev); + struct lm3533_bl *bl = dev_get_drvdata(dev); - dev_dbg(&pdev->dev, "%s\n", __func__); + dev_dbg(dev, "%s\n", __func__); return lm3533_ctrlbank_enable(&bl->cb); } -#else -#define lm3533_bl_suspend NULL -#define lm3533_bl_resume NULL #endif +static SIMPLE_DEV_PM_OPS(lm3533_bl_pm_ops, lm3533_bl_suspend, lm3533_bl_resume); + static void lm3533_bl_shutdown(struct platform_device *pdev) { struct lm3533_bl *bl = platform_get_drvdata(pdev); @@ -408,12 +398,11 @@ static struct platform_driver lm3533_bl_driver = { .driver = { .name = "lm3533-backlight", .owner = THIS_MODULE, + .pm = &lm3533_bl_pm_ops, }, .probe = lm3533_bl_probe, - .remove = __devexit_p(lm3533_bl_remove), + .remove = lm3533_bl_remove, .shutdown = lm3533_bl_shutdown, - .suspend = lm3533_bl_suspend, - .resume = lm3533_bl_resume, }; module_platform_driver(lm3533_bl_driver); diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c new file mode 100644 index 00000000000..35fe4825a45 --- /dev/null +++ b/drivers/video/backlight/lm3630a_bl.c @@ -0,0 +1,483 @@ +/* +* Simple driver for Texas Instruments LM3630A Backlight driver chip +* Copyright (C) 2012 Texas Instruments +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/pwm.h> +#include <linux/platform_data/lm3630a_bl.h> + +#define REG_CTRL 0x00 +#define REG_BOOST 0x02 +#define REG_CONFIG 0x01 +#define REG_BRT_A 0x03 +#define REG_BRT_B 0x04 +#define REG_I_A 0x05 +#define REG_I_B 0x06 +#define REG_INT_STATUS 0x09 +#define REG_INT_EN 0x0A +#define REG_FAULT 0x0B +#define REG_PWM_OUTLOW 0x12 +#define REG_PWM_OUTHIGH 0x13 +#define REG_MAX 0x1F + +#define INT_DEBOUNCE_MSEC 10 +struct lm3630a_chip { + struct device *dev; + struct delayed_work work; + + int irq; + struct workqueue_struct *irqthread; + struct lm3630a_platform_data *pdata; + struct backlight_device *bleda; + struct backlight_device *bledb; + struct regmap *regmap; + struct pwm_device *pwmd; +}; + +/* i2c access */ +static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg) +{ + int rval; + unsigned int reg_val; + + rval = regmap_read(pchip->regmap, reg, ®_val); + if (rval < 0) + return rval; + return reg_val & 0xFF; +} + +static int lm3630a_write(struct lm3630a_chip *pchip, + unsigned int reg, unsigned int data) +{ + return regmap_write(pchip->regmap, reg, data); +} + +static int lm3630a_update(struct lm3630a_chip *pchip, + unsigned int reg, unsigned int mask, + unsigned int data) +{ + return regmap_update_bits(pchip->regmap, reg, mask, data); +} + +/* initialize chip */ +static int lm3630a_chip_init(struct lm3630a_chip *pchip) +{ + int rval; + struct lm3630a_platform_data *pdata = pchip->pdata; + + usleep_range(1000, 2000); + /* set Filter Strength Register */ + rval = lm3630a_write(pchip, 0x50, 0x03); + /* set Cofig. register */ + rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl); + /* set boost control */ + rval |= lm3630a_write(pchip, REG_BOOST, 0x38); + /* set current A */ + rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F); + /* set current B */ + rval |= lm3630a_write(pchip, REG_I_B, 0x1F); + /* set control */ + rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl); + rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl); + usleep_range(1000, 2000); + /* set brightness A and B */ + rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); + rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt); + + if (rval < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + return rval; +} + +/* interrupt handling */ +static void lm3630a_delayed_func(struct work_struct *work) +{ + int rval; + struct lm3630a_chip *pchip; + + pchip = container_of(work, struct lm3630a_chip, work.work); + + rval = lm3630a_read(pchip, REG_INT_STATUS); + if (rval < 0) { + dev_err(pchip->dev, + "i2c failed to access REG_INT_STATUS Register\n"); + return; + } + + dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval); +} + +static irqreturn_t lm3630a_isr_func(int irq, void *chip) +{ + int rval; + struct lm3630a_chip *pchip = chip; + unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); + + queue_delayed_work(pchip->irqthread, &pchip->work, delay); + + rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (rval < 0) { + dev_err(pchip->dev, "i2c failed to access register\n"); + return IRQ_NONE; + } + return IRQ_HANDLED; +} + +static int lm3630a_intr_config(struct lm3630a_chip *pchip) +{ + int rval; + + rval = lm3630a_write(pchip, REG_INT_EN, 0x87); + if (rval < 0) + return rval; + + INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func); + pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd"); + if (!pchip->irqthread) { + dev_err(pchip->dev, "create irq thread fail\n"); + return -ENOMEM; + } + if (request_threaded_irq + (pchip->irq, NULL, lm3630a_isr_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { + dev_err(pchip->dev, "request threaded irq fail\n"); + destroy_workqueue(pchip->irqthread); + return -ENOMEM; + } + return rval; +} + +static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) +{ + unsigned int period = pwm_get_period(pchip->pwmd); + unsigned int duty = br * period / br_max; + + pwm_config(pchip->pwmd, duty, period); + if (duty) + pwm_enable(pchip->pwmd); + else + pwm_disable(pchip->pwmd); +} + +/* update and get brightness */ +static int lm3630a_bank_a_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + /* pwm control */ + if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { + lm3630a_pwm_ctrl(pchip, bl->props.brightness, + bl->props.max_brightness); + return bl->props.brightness; + } + + /* disable sleep */ + ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + /* minimum brightness is 0x04 */ + ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness); + if (bl->props.brightness < 0x4) + ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); + else + ret |= lm3630a_update(pchip, REG_CTRL, + LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); + if (ret < 0) + goto out_i2c_err; + return bl->props.brightness; + +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access\n"); + return bl->props.brightness; +} + +static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) +{ + int brightness, rval; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { + rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); + if (rval < 0) + goto out_i2c_err; + brightness = (rval & 0x01) << 8; + rval = lm3630a_read(pchip, REG_PWM_OUTLOW); + if (rval < 0) + goto out_i2c_err; + brightness |= rval; + goto out; + } + + /* disable sleep */ + rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (rval < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + rval = lm3630a_read(pchip, REG_BRT_A); + if (rval < 0) + goto out_i2c_err; + brightness = rval; + +out: + bl->props.brightness = brightness; + return bl->props.brightness; +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +} + +static const struct backlight_ops lm3630a_bank_a_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630a_bank_a_update_status, + .get_brightness = lm3630a_bank_a_get_brightness, +}; + +/* update and get brightness */ +static int lm3630a_bank_b_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + /* pwm control */ + if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { + lm3630a_pwm_ctrl(pchip, bl->props.brightness, + bl->props.max_brightness); + return bl->props.brightness; + } + + /* disable sleep */ + ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + /* minimum brightness is 0x04 */ + ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness); + if (bl->props.brightness < 0x4) + ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); + else + ret |= lm3630a_update(pchip, REG_CTRL, + LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); + if (ret < 0) + goto out_i2c_err; + return bl->props.brightness; + +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); + return bl->props.brightness; +} + +static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) +{ + int brightness, rval; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { + rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); + if (rval < 0) + goto out_i2c_err; + brightness = (rval & 0x01) << 8; + rval = lm3630a_read(pchip, REG_PWM_OUTLOW); + if (rval < 0) + goto out_i2c_err; + brightness |= rval; + goto out; + } + + /* disable sleep */ + rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (rval < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + rval = lm3630a_read(pchip, REG_BRT_B); + if (rval < 0) + goto out_i2c_err; + brightness = rval; + +out: + bl->props.brightness = brightness; + return bl->props.brightness; +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +} + +static const struct backlight_ops lm3630a_bank_b_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630a_bank_b_update_status, + .get_brightness = lm3630a_bank_b_get_brightness, +}; + +static int lm3630a_backlight_register(struct lm3630a_chip *pchip) +{ + struct backlight_properties props; + struct lm3630a_platform_data *pdata = pchip->pdata; + + props.type = BACKLIGHT_RAW; + if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { + props.brightness = pdata->leda_init_brt; + props.max_brightness = pdata->leda_max_brt; + pchip->bleda = + devm_backlight_device_register(pchip->dev, "lm3630a_leda", + pchip->dev, pchip, + &lm3630a_bank_a_ops, &props); + if (IS_ERR(pchip->bleda)) + return PTR_ERR(pchip->bleda); + } + + if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) && + (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) { + props.brightness = pdata->ledb_init_brt; + props.max_brightness = pdata->ledb_max_brt; + pchip->bledb = + devm_backlight_device_register(pchip->dev, "lm3630a_ledb", + pchip->dev, pchip, + &lm3630a_bank_b_ops, &props); + if (IS_ERR(pchip->bledb)) + return PTR_ERR(pchip->bledb); + } + return 0; +} + +static const struct regmap_config lm3630a_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int lm3630a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev); + struct lm3630a_chip *pchip; + int rval; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "fail : i2c functionality check\n"); + return -EOPNOTSUPP; + } + + pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip), + GFP_KERNEL); + if (!pchip) + return -ENOMEM; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap); + if (IS_ERR(pchip->regmap)) { + rval = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval); + return rval; + } + + i2c_set_clientdata(client, pchip); + if (pdata == NULL) { + pdata = devm_kzalloc(pchip->dev, + sizeof(struct lm3630a_platform_data), + GFP_KERNEL); + if (pdata == NULL) + return -ENOMEM; + /* default values */ + pdata->leda_ctrl = LM3630A_LEDA_ENABLE; + pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; + pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; + pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; + pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; + pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; + } + pchip->pdata = pdata; + + /* chip initialize */ + rval = lm3630a_chip_init(pchip); + if (rval < 0) { + dev_err(&client->dev, "fail : init chip\n"); + return rval; + } + /* backlight register */ + rval = lm3630a_backlight_register(pchip); + if (rval < 0) { + dev_err(&client->dev, "fail : backlight register.\n"); + return rval; + } + /* pwm */ + if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { + pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); + if (IS_ERR(pchip->pwmd)) { + dev_err(&client->dev, "fail : get pwm device\n"); + return PTR_ERR(pchip->pwmd); + } + } + pchip->pwmd->period = pdata->pwm_period; + + /* interrupt enable : irq 0 is not allowed */ + pchip->irq = client->irq; + if (pchip->irq) { + rval = lm3630a_intr_config(pchip); + if (rval < 0) + return rval; + } + dev_info(&client->dev, "LM3630A backlight register OK.\n"); + return 0; +} + +static int lm3630a_remove(struct i2c_client *client) +{ + int rval; + struct lm3630a_chip *pchip = i2c_get_clientdata(client); + + rval = lm3630a_write(pchip, REG_BRT_A, 0); + if (rval < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + rval = lm3630a_write(pchip, REG_BRT_B, 0); + if (rval < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + if (pchip->irq) { + free_irq(pchip->irq, pchip); + flush_workqueue(pchip->irqthread); + destroy_workqueue(pchip->irqthread); + } + return 0; +} + +static const struct i2c_device_id lm3630a_id[] = { + {LM3630A_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3630a_id); + +static struct i2c_driver lm3630a_i2c_driver = { + .driver = { + .name = LM3630A_NAME, + }, + .probe = lm3630a_probe, + .remove = lm3630a_remove, + .id_table = lm3630a_id, +}; + +module_i2c_driver(lm3630a_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A"); +MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); +MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c new file mode 100644 index 00000000000..5f36808d214 --- /dev/null +++ b/drivers/video/backlight/lm3639_bl.c @@ -0,0 +1,434 @@ +/* +* Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip +* Copyright (C) 2012 Texas Instruments +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/platform_data/lm3639_bl.h> + +#define REG_DEV_ID 0x00 +#define REG_CHECKSUM 0x01 +#define REG_BL_CONF_1 0x02 +#define REG_BL_CONF_2 0x03 +#define REG_BL_CONF_3 0x04 +#define REG_BL_CONF_4 0x05 +#define REG_FL_CONF_1 0x06 +#define REG_FL_CONF_2 0x07 +#define REG_FL_CONF_3 0x08 +#define REG_IO_CTRL 0x09 +#define REG_ENABLE 0x0A +#define REG_FLAG 0x0B +#define REG_MAX REG_FLAG + +struct lm3639_chip_data { + struct device *dev; + struct lm3639_platform_data *pdata; + + struct backlight_device *bled; + struct led_classdev cdev_flash; + struct led_classdev cdev_torch; + struct regmap *regmap; + + unsigned int bled_mode; + unsigned int bled_map; + unsigned int last_flag; +}; + +/* initialize chip */ +static int lm3639_chip_init(struct lm3639_chip_data *pchip) +{ + int ret; + unsigned int reg_val; + struct lm3639_platform_data *pdata = pchip->pdata; + + /* input pins config. */ + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08, + pdata->pin_pwm); + if (ret < 0) + goto out; + + reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx; + ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val); + if (ret < 0) + goto out; + + /* init brightness */ + ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led); + if (ret < 0) + goto out; + + ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led); + if (ret < 0) + goto out; + + /* output pins config. */ + if (!pdata->init_brt_led) { + reg_val = pdata->fled_pins; + reg_val |= pdata->bled_pins; + } else { + reg_val = pdata->fled_pins; + reg_val |= pdata->bled_pins | 0x01; + } + + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); + if (ret < 0) + goto out; + + return ret; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return ret; +} + +/* update and get brightness */ +static int lm3639_bled_update_status(struct backlight_device *bl) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip = bl_get_data(bl); + struct lm3639_platform_data *pdata = pchip->pdata; + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* pwm control */ + if (pdata->pin_pwm) { + if (pdata->pwm_set_intensity) + pdata->pwm_set_intensity(bl->props.brightness, + pdata->max_brt_led); + else + dev_err(pchip->dev, + "No pwm control func. in plat-data\n"); + return bl->props.brightness; + } + + /* i2c control and set brigtness */ + ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness); + if (ret < 0) + goto out; + ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness); + if (ret < 0) + goto out; + + if (!bl->props.brightness) + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00); + else + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01); + if (ret < 0) + goto out; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access registers\n"); + return bl->props.brightness; +} + +static int lm3639_bled_get_brightness(struct backlight_device *bl) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip = bl_get_data(bl); + struct lm3639_platform_data *pdata = pchip->pdata; + + if (pdata->pin_pwm) { + if (pdata->pwm_get_intensity) + bl->props.brightness = pdata->pwm_get_intensity(); + else + dev_err(pchip->dev, + "No pwm control func. in plat-data\n"); + return bl->props.brightness; + } + + ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val); + if (ret < 0) + goto out; + if (reg_val & 0x10) + ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val); + else + ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val); + if (ret < 0) + goto out; + bl->props.brightness = reg_val; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static const struct backlight_ops lm3639_bled_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3639_bled_update_status, + .get_brightness = lm3639_bled_get_brightness, +}; + +/* backlight mapping mode */ +static ssize_t lm3639_bled_mode_store(struct device *dev, + struct device_attribute *devAttr, + const char *buf, size_t size) +{ + ssize_t ret; + struct lm3639_chip_data *pchip = dev_get_drvdata(dev); + unsigned int state; + + ret = kstrtouint(buf, 10, &state); + if (ret) + goto out_input; + + if (!state) + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, + 0x00); + else + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, + 0x10); + + if (ret < 0) + goto out; + + return size; + +out: + dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__); + return ret; + +out_input: + dev_err(pchip->dev, "%s:input conversion fail\n", __func__); + return ret; + +} + +static DEVICE_ATTR(bled_mode, S_IWUSR, NULL, lm3639_bled_mode_store); + +/* torch */ +static void lm3639_torch_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip; + + pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch); + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* brightness 0 means off state */ + if (!brightness) { + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); + if (ret < 0) + goto out; + return; + } + + ret = regmap_update_bits(pchip->regmap, + REG_FL_CONF_1, 0x70, (brightness - 1) << 4); + if (ret < 0) + goto out; + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02); + if (ret < 0) + goto out; + + return; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return; +} + +/* flash */ +static void lm3639_flash_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip; + + pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash); + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* torch off before flash control */ + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); + if (ret < 0) + goto out; + + /* brightness 0 means off state */ + if (!brightness) + return; + + ret = regmap_update_bits(pchip->regmap, + REG_FL_CONF_1, 0x0F, brightness - 1); + if (ret < 0) + goto out; + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06); + if (ret < 0) + goto out; + + return; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return; +} + +static const struct regmap_config lm3639_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int lm3639_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct lm3639_chip_data *pchip; + struct lm3639_platform_data *pdata = dev_get_platdata(&client->dev); + struct backlight_properties props; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c functionality check fail.\n"); + return -EOPNOTSUPP; + } + + if (pdata == NULL) { + dev_err(&client->dev, "Needs Platform Data.\n"); + return -ENODATA; + } + + pchip = devm_kzalloc(&client->dev, + sizeof(struct lm3639_chip_data), GFP_KERNEL); + if (!pchip) + return -ENOMEM; + + pchip->pdata = pdata; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate register map: %d\n", + ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + /* chip initialize */ + ret = lm3639_chip_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail : chip init\n"); + goto err_out; + } + + /* backlight */ + props.type = BACKLIGHT_RAW; + props.brightness = pdata->init_brt_led; + props.max_brightness = pdata->max_brt_led; + pchip->bled = + devm_backlight_device_register(pchip->dev, "lm3639_bled", + pchip->dev, pchip, &lm3639_bled_ops, + &props); + if (IS_ERR(pchip->bled)) { + dev_err(&client->dev, "fail : backlight register\n"); + ret = PTR_ERR(pchip->bled); + goto err_out; + } + + ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); + if (ret < 0) { + dev_err(&client->dev, "failed : add sysfs entries\n"); + goto err_out; + } + + /* flash */ + pchip->cdev_flash.name = "lm3639_flash"; + pchip->cdev_flash.max_brightness = 16; + pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set; + ret = led_classdev_register((struct device *) + &client->dev, &pchip->cdev_flash); + if (ret < 0) { + dev_err(&client->dev, "fail : flash register\n"); + goto err_flash; + } + + /* torch */ + pchip->cdev_torch.name = "lm3639_torch"; + pchip->cdev_torch.max_brightness = 8; + pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set; + ret = led_classdev_register((struct device *) + &client->dev, &pchip->cdev_torch); + if (ret < 0) { + dev_err(&client->dev, "fail : torch register\n"); + goto err_torch; + } + + return 0; + +err_torch: + led_classdev_unregister(&pchip->cdev_flash); +err_flash: + device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); +err_out: + return ret; +} + +static int lm3639_remove(struct i2c_client *client) +{ + struct lm3639_chip_data *pchip = i2c_get_clientdata(client); + + regmap_write(pchip->regmap, REG_ENABLE, 0x00); + + if (&pchip->cdev_torch) + led_classdev_unregister(&pchip->cdev_torch); + if (&pchip->cdev_flash) + led_classdev_unregister(&pchip->cdev_flash); + if (pchip->bled) + device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); + return 0; +} + +static const struct i2c_device_id lm3639_id[] = { + {LM3639_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3639_id); +static struct i2c_driver lm3639_i2c_driver = { + .driver = { + .name = LM3639_NAME, + }, + .probe = lm3639_probe, + .remove = lm3639_remove, + .id_table = lm3639_id, +}; + +module_i2c_driver(lm3639_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); +MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); +MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index a9f2c36966f..14590c54aed 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -31,7 +31,7 @@ struct lms283gf05_seq { }; /* Magic sequences supplied by manufacturer, for details refer to datasheet */ -static struct lms283gf05_seq disp_initseq[] = { +static const struct lms283gf05_seq disp_initseq[] = { /* REG, VALUE, DELAY */ { 0x07, 0x0000, 0 }, { 0x13, 0x0000, 10 }, @@ -78,7 +78,7 @@ static struct lms283gf05_seq disp_initseq[] = { { 0x22, 0x0000, 0 } }; -static struct lms283gf05_seq disp_pdwnseq[] = { +static const struct lms283gf05_seq disp_pdwnseq[] = { { 0x07, 0x0016, 30 }, { 0x07, 0x0004, 0 }, @@ -104,7 +104,7 @@ static void lms283gf05_reset(unsigned long gpio, bool inverted) } static void lms283gf05_toggle(struct spi_device *spi, - struct lms283gf05_seq *seq, int sz) + const struct lms283gf05_seq *seq, int sz) { char buf[3]; int i; @@ -128,7 +128,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) { struct lms283gf05_state *st = lcd_get_data(ld); struct spi_device *spi = st->spi; - struct lms283gf05_pdata *pdata = spi->dev.platform_data; + struct lms283gf05_pdata *pdata = dev_get_platdata(&spi->dev); if (power <= FB_BLANK_NORMAL) { if (pdata) @@ -150,42 +150,36 @@ static struct lcd_ops lms_ops = { .get_power = NULL, }; -static int __devinit lms283gf05_probe(struct spi_device *spi) +static int lms283gf05_probe(struct spi_device *spi) { struct lms283gf05_state *st; - struct lms283gf05_pdata *pdata = spi->dev.platform_data; + struct lms283gf05_pdata *pdata = dev_get_platdata(&spi->dev); struct lcd_device *ld; int ret = 0; if (pdata != NULL) { - ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET"); + ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio, + GPIOF_DIR_OUT | (!pdata->reset_inverted ? + GPIOF_INIT_HIGH : GPIOF_INIT_LOW), + "LMS285GF05 RESET"); if (ret) return ret; - - ret = gpio_direction_output(pdata->reset_gpio, - !pdata->reset_inverted); - if (ret) - goto err; } st = devm_kzalloc(&spi->dev, sizeof(struct lms283gf05_state), GFP_KERNEL); - if (st == NULL) { - dev_err(&spi->dev, "No memory for device state\n"); - ret = -ENOMEM; - goto err; - } + if (st == NULL) + return -ENOMEM; - ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops); - if (IS_ERR(ld)) { - ret = PTR_ERR(ld); - goto err; - } + ld = devm_lcd_device_register(&spi->dev, "lms283gf05", &spi->dev, st, + &lms_ops); + if (IS_ERR(ld)) + return PTR_ERR(ld); st->spi = spi; st->ld = ld; - dev_set_drvdata(&spi->dev, st); + spi_set_drvdata(spi, st); /* kick in the LCD */ if (pdata) @@ -193,25 +187,6 @@ static int __devinit lms283gf05_probe(struct spi_device *spi) lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq)); return 0; - -err: - if (pdata != NULL) - gpio_free(pdata->reset_gpio); - - return ret; -} - -static int __devexit lms283gf05_remove(struct spi_device *spi) -{ - struct lms283gf05_state *st = dev_get_drvdata(&spi->dev); - struct lms283gf05_pdata *pdata = st->spi->dev.platform_data; - - lcd_device_unregister(st->ld); - - if (pdata != NULL) - gpio_free(pdata->reset_gpio); - - return 0; } static struct spi_driver lms283gf05_driver = { @@ -220,7 +195,6 @@ static struct spi_driver lms283gf05_driver = { .owner = THIS_MODULE, }, .probe = lms283gf05_probe, - .remove = __devexit_p(lms283gf05_remove), }; module_spi_driver(lms283gf05_driver); diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c new file mode 100644 index 00000000000..77258b7b04b --- /dev/null +++ b/drivers/video/backlight/lms501kf03.c @@ -0,0 +1,437 @@ +/* + * lms501kf03 TFT LCD panel driver. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * Author: Jingoo Han <jg1.han@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/lcd.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/wait.h> + +#define COMMAND_ONLY 0x00 +#define DATA_ONLY 0x01 + +struct lms501kf03 { + struct device *dev; + struct spi_device *spi; + unsigned int power; + struct lcd_device *ld; + struct lcd_platform_data *lcd_pd; +}; + +static const unsigned char seq_password[] = { + 0xb9, 0xff, 0x83, 0x69, +}; + +static const unsigned char seq_power[] = { + 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28, + 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, +}; + +static const unsigned char seq_display[] = { + 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x03, 0x00, 0x01, +}; + +static const unsigned char seq_rgb_if[] = { + 0xb3, 0x09, +}; + +static const unsigned char seq_display_inv[] = { + 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06, +}; + +static const unsigned char seq_vcom[] = { + 0xb6, 0x4c, 0x2e, +}; + +static const unsigned char seq_gate[] = { + 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13, + 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75, + 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07, +}; + +static const unsigned char seq_panel[] = { + 0xcc, 0x02, +}; + +static const unsigned char seq_col_mod[] = { + 0x3a, 0x77, +}; + +static const unsigned char seq_w_gamma[] = { + 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a, + 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04, + 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16, + 0x18, 0x16, 0x17, 0x0d, 0x15, +}; + +static const unsigned char seq_rgb_gamma[] = { + 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c, + 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92, + 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde, + 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb, + 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a, + 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, + 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca, + 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe, + 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17, + 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63, + 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0, + 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char seq_up_dn[] = { + 0x36, 0x10, +}; + +static const unsigned char seq_sleep_in[] = { + 0x10, +}; + +static const unsigned char seq_sleep_out[] = { + 0x11, +}; + +static const unsigned char seq_display_on[] = { + 0x29, +}; + +static const unsigned char seq_display_off[] = { + 0x10, +}; + +static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data) +{ + u16 buf[1]; + struct spi_message msg; + + struct spi_transfer xfer = { + .len = 2, + .tx_buf = buf, + }; + + buf[0] = (addr << 8) | data; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address, + unsigned char command) +{ + return lms501kf03_spi_write_byte(lcd, address, command); +} + +static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd, + const unsigned char *wbuf, + unsigned int len) +{ + int ret = 0, i = 0; + + while (i < len) { + if (i == 0) + ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]); + else + ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]); + if (ret) + break; + i += 1; + } + + return ret; +} + +static int lms501kf03_ldi_init(struct lms501kf03 *lcd) +{ + int ret, i; + static const unsigned char *init_seq[] = { + seq_password, + seq_power, + seq_display, + seq_rgb_if, + seq_display_inv, + seq_vcom, + seq_gate, + seq_panel, + seq_col_mod, + seq_w_gamma, + seq_rgb_gamma, + seq_sleep_out, + }; + + static const unsigned int size_seq[] = { + ARRAY_SIZE(seq_password), + ARRAY_SIZE(seq_power), + ARRAY_SIZE(seq_display), + ARRAY_SIZE(seq_rgb_if), + ARRAY_SIZE(seq_display_inv), + ARRAY_SIZE(seq_vcom), + ARRAY_SIZE(seq_gate), + ARRAY_SIZE(seq_panel), + ARRAY_SIZE(seq_col_mod), + ARRAY_SIZE(seq_w_gamma), + ARRAY_SIZE(seq_rgb_gamma), + ARRAY_SIZE(seq_sleep_out), + }; + + for (i = 0; i < ARRAY_SIZE(init_seq); i++) { + ret = lms501kf03_panel_send_sequence(lcd, init_seq[i], + size_seq[i]); + if (ret) + break; + } + /* + * According to the datasheet, 120ms delay time is required. + * After sleep out sequence, command is blocked for 120ms. + * Thus, LDI should wait for 120ms. + */ + msleep(120); + + return ret; +} + +static int lms501kf03_ldi_enable(struct lms501kf03 *lcd) +{ + return lms501kf03_panel_send_sequence(lcd, seq_display_on, + ARRAY_SIZE(seq_display_on)); +} + +static int lms501kf03_ldi_disable(struct lms501kf03 *lcd) +{ + return lms501kf03_panel_send_sequence(lcd, seq_display_off, + ARRAY_SIZE(seq_display_off)); +} + +static int lms501kf03_power_is_on(int power) +{ + return (power) <= FB_BLANK_NORMAL; +} + +static int lms501kf03_power_on(struct lms501kf03 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd; + + pd = lcd->lcd_pd; + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EINVAL; + } else { + pd->power_on(lcd->ld, 1); + msleep(pd->power_on_delay); + } + + if (!pd->reset) { + dev_err(lcd->dev, "reset is NULL.\n"); + return -EINVAL; + } else { + pd->reset(lcd->ld); + msleep(pd->reset_delay); + } + + ret = lms501kf03_ldi_init(lcd); + if (ret) { + dev_err(lcd->dev, "failed to initialize ldi.\n"); + return ret; + } + + ret = lms501kf03_ldi_enable(lcd); + if (ret) { + dev_err(lcd->dev, "failed to enable ldi.\n"); + return ret; + } + + return 0; +} + +static int lms501kf03_power_off(struct lms501kf03 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd; + + pd = lcd->lcd_pd; + + ret = lms501kf03_ldi_disable(lcd); + if (ret) { + dev_err(lcd->dev, "lcd setting failed.\n"); + return -EIO; + } + + msleep(pd->power_off_delay); + + pd->power_on(lcd->ld, 0); + + return 0; +} + +static int lms501kf03_power(struct lms501kf03 *lcd, int power) +{ + int ret = 0; + + if (lms501kf03_power_is_on(power) && + !lms501kf03_power_is_on(lcd->power)) + ret = lms501kf03_power_on(lcd); + else if (!lms501kf03_power_is_on(power) && + lms501kf03_power_is_on(lcd->power)) + ret = lms501kf03_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int lms501kf03_get_power(struct lcd_device *ld) +{ + struct lms501kf03 *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static int lms501kf03_set_power(struct lcd_device *ld, int power) +{ + struct lms501kf03 *lcd = lcd_get_data(ld); + + if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && + power != FB_BLANK_NORMAL) { + dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); + return -EINVAL; + } + + return lms501kf03_power(lcd, power); +} + +static struct lcd_ops lms501kf03_lcd_ops = { + .get_power = lms501kf03_get_power, + .set_power = lms501kf03_set_power, +}; + +static int lms501kf03_probe(struct spi_device *spi) +{ + struct lms501kf03 *lcd = NULL; + struct lcd_device *ld = NULL; + int ret = 0; + + lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */ + spi->bits_per_word = 9; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "spi setup failed.\n"); + return ret; + } + + lcd->spi = spi; + lcd->dev = &spi->dev; + + lcd->lcd_pd = dev_get_platdata(&spi->dev); + if (!lcd->lcd_pd) { + dev_err(&spi->dev, "platform data is NULL\n"); + return -EINVAL; + } + + ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd, + &lms501kf03_lcd_ops); + if (IS_ERR(ld)) + return PTR_ERR(ld); + + lcd->ld = ld; + + if (!lcd->lcd_pd->lcd_enabled) { + /* + * if lcd panel was off from bootloader then + * current lcd status is powerdown and then + * it enables lcd panel. + */ + lcd->power = FB_BLANK_POWERDOWN; + + lms501kf03_power(lcd, FB_BLANK_UNBLANK); + } else { + lcd->power = FB_BLANK_UNBLANK; + } + + spi_set_drvdata(spi, lcd); + + dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n"); + + return 0; +} + +static int lms501kf03_remove(struct spi_device *spi) +{ + struct lms501kf03 *lcd = spi_get_drvdata(spi); + + lms501kf03_power(lcd, FB_BLANK_POWERDOWN); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int lms501kf03_suspend(struct device *dev) +{ + struct lms501kf03 *lcd = dev_get_drvdata(dev); + + dev_dbg(dev, "lcd->power = %d\n", lcd->power); + + /* + * when lcd panel is suspend, lcd panel becomes off + * regardless of status. + */ + return lms501kf03_power(lcd, FB_BLANK_POWERDOWN); +} + +static int lms501kf03_resume(struct device *dev) +{ + struct lms501kf03 *lcd = dev_get_drvdata(dev); + + lcd->power = FB_BLANK_POWERDOWN; + + return lms501kf03_power(lcd, FB_BLANK_UNBLANK); +} +#endif + +static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend, + lms501kf03_resume); + +static void lms501kf03_shutdown(struct spi_device *spi) +{ + struct lms501kf03 *lcd = spi_get_drvdata(spi); + + lms501kf03_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver lms501kf03_driver = { + .driver = { + .name = "lms501kf03", + .owner = THIS_MODULE, + .pm = &lms501kf03_pm_ops, + }, + .probe = lms501kf03_probe, + .remove = lms501kf03_remove, + .shutdown = lms501kf03_shutdown, +}; + +module_spi_driver(lms501kf03_driver); + +MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); +MODULE_DESCRIPTION("lms501kf03 LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 3a6d5419e3e..6c3ec4259a6 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -107,7 +107,6 @@ void locomolcd_power(int on) } EXPORT_SYMBOL(locomolcd_power); - static int current_intensity; static int locomolcd_set_intensity(struct backlight_device *bd) @@ -122,13 +121,25 @@ static int locomolcd_set_intensity(struct backlight_device *bd) intensity = 0; switch (intensity) { - /* AC and non-AC are handled differently, but produce same results in sharp code? */ - case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break; - case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break; - case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break; - case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break; - case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break; - + /* + * AC and non-AC are handled differently, + * but produce same results in sharp code? + */ + case 0: + locomo_frontlight_set(locomolcd_dev, 0, 0, 161); + break; + case 1: + locomo_frontlight_set(locomolcd_dev, 117, 0, 161); + break; + case 2: + locomo_frontlight_set(locomolcd_dev, 163, 0, 148); + break; + case 3: + locomo_frontlight_set(locomolcd_dev, 194, 0, 161); + break; + case 4: + locomo_frontlight_set(locomolcd_dev, 194, 1, 161); + break; default: return -ENODEV; } @@ -146,25 +157,24 @@ static const struct backlight_ops locomobl_data = { .update_status = locomolcd_set_intensity, }; -#ifdef CONFIG_PM -static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int locomolcd_suspend(struct device *dev) { locomolcd_flags |= LOCOMOLCD_SUSPENDED; locomolcd_set_intensity(locomolcd_bl_device); return 0; } -static int locomolcd_resume(struct locomo_dev *dev) +static int locomolcd_resume(struct device *dev) { locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; locomolcd_set_intensity(locomolcd_bl_device); return 0; } -#else -#define locomolcd_suspend NULL -#define locomolcd_resume NULL #endif +static SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume); + static int locomolcd_probe(struct locomo_dev *ldev) { struct backlight_properties props; @@ -175,9 +185,11 @@ static int locomolcd_probe(struct locomo_dev *ldev) locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0); - /* the poodle_lcd_power function is called for the first time + /* + * the poodle_lcd_power function is called for the first time * from fs_initcall, which is before locomo is activated. - * We need to recall poodle_lcd_power here*/ + * We need to recall poodle_lcd_power here + */ if (machine_is_poodle()) locomolcd_power(1); @@ -190,8 +202,8 @@ static int locomolcd_probe(struct locomo_dev *ldev) &ldev->dev, NULL, &locomobl_data, &props); - if (IS_ERR (locomolcd_bl_device)) - return PTR_ERR (locomolcd_bl_device); + if (IS_ERR(locomolcd_bl_device)) + return PTR_ERR(locomolcd_bl_device); /* Set up frontlight so that screen is readable */ locomolcd_bl_device->props.brightness = 2; @@ -217,16 +229,14 @@ static int locomolcd_remove(struct locomo_dev *dev) static struct locomo_driver poodle_lcd_driver = { .drv = { - .name = "locomo-backlight", + .name = "locomo-backlight", + .pm = &locomolcd_pm_ops, }, .devid = LOCOMO_DEVID_BACKLIGHT, .probe = locomolcd_probe, .remove = locomolcd_remove, - .suspend = locomolcd_suspend, - .resume = locomolcd_resume, }; - static int __init locomolcd_init(void) { return locomo_driver_register(&poodle_lcd_driver); diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 72a0e0c917c..2ca3a040007 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -14,52 +14,87 @@ #include <linux/i2c.h> #include <linux/backlight.h> #include <linux/err.h> -#include <linux/lp855x.h> +#include <linux/of.h> +#include <linux/platform_data/lp855x.h> +#include <linux/pwm.h> + +/* LP8550/1/2/3/6 Registers */ +#define LP855X_BRIGHTNESS_CTRL 0x00 +#define LP855X_DEVICE_CTRL 0x01 +#define LP855X_EEPROM_START 0xA0 +#define LP855X_EEPROM_END 0xA7 +#define LP8556_EPROM_START 0xA0 +#define LP8556_EPROM_END 0xAF + +/* LP8555/7 Registers */ +#define LP8557_BL_CMD 0x00 +#define LP8557_BL_MASK 0x01 +#define LP8557_BL_ON 0x01 +#define LP8557_BL_OFF 0x00 +#define LP8557_BRIGHTNESS_CTRL 0x04 +#define LP8557_CONFIG 0x10 +#define LP8555_EPROM_START 0x10 +#define LP8555_EPROM_END 0x7A +#define LP8557_EPROM_START 0x10 +#define LP8557_EPROM_END 0x1E -/* Registers */ -#define BRIGHTNESS_CTRL (0x00) -#define DEVICE_CTRL (0x01) - -#define BUF_SIZE 20 #define DEFAULT_BL_NAME "lcd-backlight" #define MAX_BRIGHTNESS 255 +enum lp855x_brightness_ctrl_mode { + PWM_BASED = 1, + REGISTER_BASED, +}; + +struct lp855x; + +/* + * struct lp855x_device_config + * @pre_init_device: init device function call before updating the brightness + * @reg_brightness: register address for brigthenss control + * @reg_devicectrl: register address for device control + * @post_init_device: late init device function call + */ +struct lp855x_device_config { + int (*pre_init_device)(struct lp855x *); + u8 reg_brightness; + u8 reg_devicectrl; + int (*post_init_device)(struct lp855x *); +}; + struct lp855x { const char *chipname; enum lp855x_chip_id chip_id; + enum lp855x_brightness_ctrl_mode mode; + struct lp855x_device_config *cfg; struct i2c_client *client; struct backlight_device *bl; struct device *dev; - struct mutex xfer_lock; struct lp855x_platform_data *pdata; + struct pwm_device *pwm; }; -static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data) +static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(lp->client, reg, data); +} + +static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data) { int ret; + u8 tmp; - mutex_lock(&lp->xfer_lock); ret = i2c_smbus_read_byte_data(lp->client, reg); if (ret < 0) { - mutex_unlock(&lp->xfer_lock); dev_err(lp->dev, "failed to read 0x%.2x\n", reg); return ret; } - mutex_unlock(&lp->xfer_lock); - *data = (u8)ret; - return 0; -} + tmp = (u8)ret; + tmp &= ~mask; + tmp |= data & mask; -static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data) -{ - int ret; - - mutex_lock(&lp->xfer_lock); - ret = i2c_smbus_write_byte_data(lp->client, reg, data); - mutex_unlock(&lp->xfer_lock); - - return ret; + return lp855x_write_byte(lp, reg, tmp); } static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) @@ -71,37 +106,105 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) case LP8551: case LP8552: case LP8553: - start = EEPROM_START; - end = EEPROM_END; + start = LP855X_EEPROM_START; + end = LP855X_EEPROM_END; break; case LP8556: - start = EPROM_START; - end = EPROM_END; + start = LP8556_EPROM_START; + end = LP8556_EPROM_END; + break; + case LP8555: + start = LP8555_EPROM_START; + end = LP8555_EPROM_END; + break; + case LP8557: + start = LP8557_EPROM_START; + end = LP8557_EPROM_END; break; default: return false; } - return (addr >= start && addr <= end); + return addr >= start && addr <= end; +} + +static int lp8557_bl_off(struct lp855x *lp) +{ + /* BL_ON = 0 before updating EPROM settings */ + return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK, + LP8557_BL_OFF); +} + +static int lp8557_bl_on(struct lp855x *lp) +{ + /* BL_ON = 1 after updating EPROM settings */ + return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK, + LP8557_BL_ON); } -static int lp855x_init_registers(struct lp855x *lp) +static struct lp855x_device_config lp855x_dev_cfg = { + .reg_brightness = LP855X_BRIGHTNESS_CTRL, + .reg_devicectrl = LP855X_DEVICE_CTRL, +}; + +static struct lp855x_device_config lp8557_dev_cfg = { + .reg_brightness = LP8557_BRIGHTNESS_CTRL, + .reg_devicectrl = LP8557_CONFIG, + .pre_init_device = lp8557_bl_off, + .post_init_device = lp8557_bl_on, +}; + +/* + * Device specific configuration flow + * + * a) pre_init_device(optional) + * b) update the brightness register + * c) update device control register + * d) update ROM area(optional) + * e) post_init_device(optional) + * + */ +static int lp855x_configure(struct lp855x *lp) { u8 val, addr; int i, ret; struct lp855x_platform_data *pd = lp->pdata; + switch (lp->chip_id) { + case LP8550: + case LP8551: + case LP8552: + case LP8553: + case LP8556: + lp->cfg = &lp855x_dev_cfg; + break; + case LP8555: + case LP8557: + lp->cfg = &lp8557_dev_cfg; + break; + default: + return -EINVAL; + } + + if (lp->cfg->pre_init_device) { + ret = lp->cfg->pre_init_device(lp); + if (ret) { + dev_err(lp->dev, "pre init device err: %d\n", ret); + goto err; + } + } + val = pd->initial_brightness; - ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val); + ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val); if (ret) - return ret; + goto err; val = pd->device_control; - ret = lp855x_write_byte(lp, DEVICE_CTRL, val); + ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val); if (ret) - return ret; + goto err; - if (pd->load_new_rom_data && pd->size_program) { + if (pd->size_program > 0) { for (i = 0; i < pd->size_program; i++) { addr = pd->rom_data[i].addr; val = pd->rom_data[i].val; @@ -110,32 +213,62 @@ static int lp855x_init_registers(struct lp855x *lp) ret = lp855x_write_byte(lp, addr, val); if (ret) - return ret; + goto err; } } + if (lp->cfg->post_init_device) { + ret = lp->cfg->post_init_device(lp); + if (ret) { + dev_err(lp->dev, "post init device err: %d\n", ret); + goto err; + } + } + + return 0; + +err: return ret; } +static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) +{ + unsigned int period = lp->pdata->period_ns; + unsigned int duty = br * period / max_br; + struct pwm_device *pwm; + + /* request pwm device with the consumer name */ + if (!lp->pwm) { + pwm = devm_pwm_get(lp->dev, lp->chipname); + if (IS_ERR(pwm)) + return; + + lp->pwm = pwm; + } + + pwm_config(lp->pwm, duty, period); + if (duty) + pwm_enable(lp->pwm); + else + pwm_disable(lp->pwm); +} + static int lp855x_bl_update_status(struct backlight_device *bl) { struct lp855x *lp = bl_get_data(bl); - enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode; - if (bl->props.state & BL_CORE_SUSPENDED) + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) bl->props.brightness = 0; - if (mode == PWM_BASED) { - struct lp855x_pwm_data *pd = &lp->pdata->pwm_data; + if (lp->mode == PWM_BASED) { int br = bl->props.brightness; int max_br = bl->props.max_brightness; - if (pd->pwm_set_intensity) - pd->pwm_set_intensity(br, max_br); + lp855x_pwm_ctrl(lp, br, max_br); - } else if (mode == REGISTER_BASED) { + } else if (lp->mode == REGISTER_BASED) { u8 val = bl->props.brightness; - lp855x_write_byte(lp, BRIGHTNESS_CTRL, val); + lp855x_write_byte(lp, lp->cfg->reg_brightness, val); } return 0; @@ -143,23 +276,6 @@ static int lp855x_bl_update_status(struct backlight_device *bl) static int lp855x_bl_get_brightness(struct backlight_device *bl) { - struct lp855x *lp = bl_get_data(bl); - enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode; - - if (mode == PWM_BASED) { - struct lp855x_pwm_data *pd = &lp->pdata->pwm_data; - int max_br = bl->props.max_brightness; - - if (pd->pwm_get_intensity) - bl->props.brightness = pd->pwm_get_intensity(max_br); - - } else if (mode == REGISTER_BASED) { - u8 val = 0; - - lp855x_read_byte(lp, BRIGHTNESS_CTRL, &val); - bl->props.brightness = val; - } - return bl->props.brightness; } @@ -174,7 +290,7 @@ static int lp855x_backlight_register(struct lp855x *lp) struct backlight_device *bl; struct backlight_properties props; struct lp855x_platform_data *pdata = lp->pdata; - char *name = pdata->name ? : DEFAULT_BL_NAME; + const char *name = pdata->name ? : DEFAULT_BL_NAME; props.type = BACKLIGHT_PLATFORM; props.max_brightness = MAX_BRIGHTNESS; @@ -184,7 +300,7 @@ static int lp855x_backlight_register(struct lp855x *lp) props.brightness = pdata->initial_brightness; - bl = backlight_device_register(name, lp->dev, lp, + bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp, &lp855x_bl_ops, &props); if (IS_ERR(bl)) return PTR_ERR(bl); @@ -194,32 +310,25 @@ static int lp855x_backlight_register(struct lp855x *lp) return 0; } -static void lp855x_backlight_unregister(struct lp855x *lp) -{ - if (lp->bl) - backlight_device_unregister(lp->bl); -} - static ssize_t lp855x_get_chip_id(struct device *dev, struct device_attribute *attr, char *buf) { struct lp855x *lp = dev_get_drvdata(dev); - return scnprintf(buf, BUF_SIZE, "%s\n", lp->chipname); + return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname); } static ssize_t lp855x_get_bl_ctl_mode(struct device *dev, struct device_attribute *attr, char *buf) { struct lp855x *lp = dev_get_drvdata(dev); - enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode; char *strmode = NULL; - if (mode == PWM_BASED) + if (lp->mode == PWM_BASED) strmode = "pwm based"; - else if (mode == REGISTER_BASED) + else if (lp->mode == REGISTER_BASED) strmode = "register based"; - return scnprintf(buf, BUF_SIZE, "%s\n", strmode); + return scnprintf(buf, PAGE_SIZE, "%s\n", strmode); } static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL); @@ -235,16 +344,71 @@ static const struct attribute_group lp855x_attr_group = { .attrs = lp855x_attributes, }; +#ifdef CONFIG_OF +static int lp855x_parse_dt(struct device *dev, struct device_node *node) +{ + struct lp855x_platform_data *pdata; + int rom_length; + + if (!node) { + dev_err(dev, "no platform data\n"); + return -EINVAL; + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + of_property_read_string(node, "bl-name", &pdata->name); + of_property_read_u8(node, "dev-ctrl", &pdata->device_control); + of_property_read_u8(node, "init-brt", &pdata->initial_brightness); + of_property_read_u32(node, "pwm-period", &pdata->period_ns); + + /* Fill ROM platform data if defined */ + rom_length = of_get_child_count(node); + if (rom_length > 0) { + struct lp855x_rom_data *rom; + struct device_node *child; + int i = 0; + + rom = devm_kzalloc(dev, sizeof(*rom) * rom_length, GFP_KERNEL); + if (!rom) + return -ENOMEM; + + for_each_child_of_node(node, child) { + of_property_read_u8(child, "rom-addr", &rom[i].addr); + of_property_read_u8(child, "rom-val", &rom[i].val); + i++; + } + + pdata->size_program = rom_length; + pdata->rom_data = &rom[0]; + } + + dev->platform_data = pdata; + + return 0; +} +#else +static int lp855x_parse_dt(struct device *dev, struct device_node *node) +{ + return -EINVAL; +} +#endif + static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp855x *lp; - struct lp855x_platform_data *pdata = cl->dev.platform_data; - enum lp855x_brightness_ctrl_mode mode; + struct lp855x_platform_data *pdata = dev_get_platdata(&cl->dev); + struct device_node *node = cl->dev.of_node; int ret; if (!pdata) { - dev_err(&cl->dev, "no platform data supplied\n"); - return -EINVAL; + ret = lp855x_parse_dt(&cl->dev, node); + if (ret < 0) + return ret; + + pdata = dev_get_platdata(&cl->dev); } if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) @@ -254,7 +418,11 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) if (!lp) return -ENOMEM; - mode = pdata->mode; + if (pdata->period_ns > 0) + lp->mode = PWM_BASED; + else + lp->mode = REGISTER_BASED; + lp->client = cl; lp->dev = &cl->dev; lp->pdata = pdata; @@ -262,55 +430,60 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) lp->chip_id = id->driver_data; i2c_set_clientdata(cl, lp); - mutex_init(&lp->xfer_lock); - - ret = lp855x_init_registers(lp); + ret = lp855x_configure(lp); if (ret) { - dev_err(lp->dev, "i2c communication err: %d", ret); - if (mode == REGISTER_BASED) - goto err_dev; + dev_err(lp->dev, "device config err: %d", ret); + return ret; } ret = lp855x_backlight_register(lp); if (ret) { dev_err(lp->dev, "failed to register backlight. err: %d\n", ret); - goto err_dev; + return ret; } ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group); if (ret) { dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret); - goto err_sysfs; + return ret; } backlight_update_status(lp->bl); return 0; - -err_sysfs: - lp855x_backlight_unregister(lp); -err_dev: - return ret; } -static int __devexit lp855x_remove(struct i2c_client *cl) +static int lp855x_remove(struct i2c_client *cl) { struct lp855x *lp = i2c_get_clientdata(cl); lp->bl->props.brightness = 0; backlight_update_status(lp->bl); sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group); - lp855x_backlight_unregister(lp); return 0; } +static const struct of_device_id lp855x_dt_ids[] = { + { .compatible = "ti,lp8550", }, + { .compatible = "ti,lp8551", }, + { .compatible = "ti,lp8552", }, + { .compatible = "ti,lp8553", }, + { .compatible = "ti,lp8555", }, + { .compatible = "ti,lp8556", }, + { .compatible = "ti,lp8557", }, + { } +}; +MODULE_DEVICE_TABLE(of, lp855x_dt_ids); + static const struct i2c_device_id lp855x_ids[] = { {"lp8550", LP8550}, {"lp8551", LP8551}, {"lp8552", LP8552}, {"lp8553", LP8553}, + {"lp8555", LP8555}, {"lp8556", LP8556}, + {"lp8557", LP8557}, { } }; MODULE_DEVICE_TABLE(i2c, lp855x_ids); @@ -318,9 +491,10 @@ MODULE_DEVICE_TABLE(i2c, lp855x_ids); static struct i2c_driver lp855x_driver = { .driver = { .name = "lp855x", + .of_match_table = of_match_ptr(lp855x_dt_ids), }, .probe = lp855x_probe, - .remove = __devexit_p(lp855x_remove), + .remove = lp855x_remove, .id_table = lp855x_ids, }; diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c new file mode 100644 index 00000000000..daba34dc46d --- /dev/null +++ b/drivers/video/backlight/lp8788_bl.c @@ -0,0 +1,332 @@ +/* + * TI LP8788 MFD - backlight driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/mfd/lp8788.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> + +/* Register address */ +#define LP8788_BL_CONFIG 0x96 +#define LP8788_BL_EN BIT(0) +#define LP8788_BL_PWM_INPUT_EN BIT(5) +#define LP8788_BL_FULLSCALE_SHIFT 2 +#define LP8788_BL_DIM_MODE_SHIFT 1 +#define LP8788_BL_PWM_POLARITY_SHIFT 6 + +#define LP8788_BL_BRIGHTNESS 0x97 + +#define LP8788_BL_RAMP 0x98 +#define LP8788_BL_RAMP_RISE_SHIFT 4 + +#define MAX_BRIGHTNESS 127 +#define DEFAULT_BL_NAME "lcd-backlight" + +struct lp8788_bl_config { + enum lp8788_bl_ctrl_mode bl_mode; + enum lp8788_bl_dim_mode dim_mode; + enum lp8788_bl_full_scale_current full_scale; + enum lp8788_bl_ramp_step rise_time; + enum lp8788_bl_ramp_step fall_time; + enum pwm_polarity pwm_pol; +}; + +struct lp8788_bl { + struct lp8788 *lp; + struct backlight_device *bl_dev; + struct lp8788_backlight_platform_data *pdata; + enum lp8788_bl_ctrl_mode mode; + struct pwm_device *pwm; +}; + +static struct lp8788_bl_config default_bl_config = { + .bl_mode = LP8788_BL_REGISTER_ONLY, + .dim_mode = LP8788_DIM_EXPONENTIAL, + .full_scale = LP8788_FULLSCALE_1900uA, + .rise_time = LP8788_RAMP_8192us, + .fall_time = LP8788_RAMP_8192us, + .pwm_pol = PWM_POLARITY_NORMAL, +}; + +static inline bool is_brightness_ctrl_by_pwm(enum lp8788_bl_ctrl_mode mode) +{ + return mode == LP8788_BL_COMB_PWM_BASED; +} + +static inline bool is_brightness_ctrl_by_register(enum lp8788_bl_ctrl_mode mode) +{ + return mode == LP8788_BL_REGISTER_ONLY || + mode == LP8788_BL_COMB_REGISTER_BASED; +} + +static int lp8788_backlight_configure(struct lp8788_bl *bl) +{ + struct lp8788_backlight_platform_data *pdata = bl->pdata; + struct lp8788_bl_config *cfg = &default_bl_config; + int ret; + u8 val; + + /* + * Update chip configuration if platform data exists, + * otherwise use the default settings. + */ + if (pdata) { + cfg->bl_mode = pdata->bl_mode; + cfg->dim_mode = pdata->dim_mode; + cfg->full_scale = pdata->full_scale; + cfg->rise_time = pdata->rise_time; + cfg->fall_time = pdata->fall_time; + cfg->pwm_pol = pdata->pwm_pol; + } + + /* Brightness ramp up/down */ + val = (cfg->rise_time << LP8788_BL_RAMP_RISE_SHIFT) | cfg->fall_time; + ret = lp8788_write_byte(bl->lp, LP8788_BL_RAMP, val); + if (ret) + return ret; + + /* Fullscale current setting */ + val = (cfg->full_scale << LP8788_BL_FULLSCALE_SHIFT) | + (cfg->dim_mode << LP8788_BL_DIM_MODE_SHIFT); + + /* Brightness control mode */ + switch (cfg->bl_mode) { + case LP8788_BL_REGISTER_ONLY: + val |= LP8788_BL_EN; + break; + case LP8788_BL_COMB_PWM_BASED: + case LP8788_BL_COMB_REGISTER_BASED: + val |= LP8788_BL_EN | LP8788_BL_PWM_INPUT_EN | + (cfg->pwm_pol << LP8788_BL_PWM_POLARITY_SHIFT); + break; + default: + dev_err(bl->lp->dev, "invalid mode: %d\n", cfg->bl_mode); + return -EINVAL; + } + + bl->mode = cfg->bl_mode; + + return lp8788_write_byte(bl->lp, LP8788_BL_CONFIG, val); +} + +static void lp8788_pwm_ctrl(struct lp8788_bl *bl, int br, int max_br) +{ + unsigned int period; + unsigned int duty; + struct device *dev; + struct pwm_device *pwm; + + if (!bl->pdata) + return; + + period = bl->pdata->period_ns; + duty = br * period / max_br; + dev = bl->lp->dev; + + /* request PWM device with the consumer name */ + if (!bl->pwm) { + pwm = devm_pwm_get(dev, LP8788_DEV_BACKLIGHT); + if (IS_ERR(pwm)) { + dev_err(dev, "can not get PWM device\n"); + return; + } + + bl->pwm = pwm; + } + + pwm_config(bl->pwm, duty, period); + if (duty) + pwm_enable(bl->pwm); + else + pwm_disable(bl->pwm); +} + +static int lp8788_bl_update_status(struct backlight_device *bl_dev) +{ + struct lp8788_bl *bl = bl_get_data(bl_dev); + enum lp8788_bl_ctrl_mode mode = bl->mode; + + if (bl_dev->props.state & BL_CORE_SUSPENDED) + bl_dev->props.brightness = 0; + + if (is_brightness_ctrl_by_pwm(mode)) { + int brt = bl_dev->props.brightness; + int max = bl_dev->props.max_brightness; + + lp8788_pwm_ctrl(bl, brt, max); + } else if (is_brightness_ctrl_by_register(mode)) { + u8 brt = bl_dev->props.brightness; + + lp8788_write_byte(bl->lp, LP8788_BL_BRIGHTNESS, brt); + } + + return 0; +} + +static int lp8788_bl_get_brightness(struct backlight_device *bl_dev) +{ + return bl_dev->props.brightness; +} + +static const struct backlight_ops lp8788_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lp8788_bl_update_status, + .get_brightness = lp8788_bl_get_brightness, +}; + +static int lp8788_backlight_register(struct lp8788_bl *bl) +{ + struct backlight_device *bl_dev; + struct backlight_properties props; + struct lp8788_backlight_platform_data *pdata = bl->pdata; + int init_brt; + char *name; + + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = MAX_BRIGHTNESS; + + /* Initial brightness */ + if (pdata) + init_brt = min_t(int, pdata->initial_brightness, + props.max_brightness); + else + init_brt = 0; + + props.brightness = init_brt; + + /* Backlight device name */ + if (!pdata || !pdata->name) + name = DEFAULT_BL_NAME; + else + name = pdata->name; + + bl_dev = backlight_device_register(name, bl->lp->dev, bl, + &lp8788_bl_ops, &props); + if (IS_ERR(bl_dev)) + return PTR_ERR(bl_dev); + + bl->bl_dev = bl_dev; + + return 0; +} + +static void lp8788_backlight_unregister(struct lp8788_bl *bl) +{ + struct backlight_device *bl_dev = bl->bl_dev; + + if (bl_dev) + backlight_device_unregister(bl_dev); +} + +static ssize_t lp8788_get_bl_ctl_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lp8788_bl *bl = dev_get_drvdata(dev); + enum lp8788_bl_ctrl_mode mode = bl->mode; + char *strmode; + + if (is_brightness_ctrl_by_pwm(mode)) + strmode = "PWM based"; + else if (is_brightness_ctrl_by_register(mode)) + strmode = "Register based"; + else + strmode = "Invalid mode"; + + return scnprintf(buf, PAGE_SIZE, "%s\n", strmode); +} + +static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp8788_get_bl_ctl_mode, NULL); + +static struct attribute *lp8788_attributes[] = { + &dev_attr_bl_ctl_mode.attr, + NULL, +}; + +static const struct attribute_group lp8788_attr_group = { + .attrs = lp8788_attributes, +}; + +static int lp8788_backlight_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + struct lp8788_bl *bl; + int ret; + + bl = devm_kzalloc(lp->dev, sizeof(struct lp8788_bl), GFP_KERNEL); + if (!bl) + return -ENOMEM; + + bl->lp = lp; + if (lp->pdata) + bl->pdata = lp->pdata->bl_pdata; + + platform_set_drvdata(pdev, bl); + + ret = lp8788_backlight_configure(bl); + if (ret) { + dev_err(lp->dev, "backlight config err: %d\n", ret); + goto err_dev; + } + + ret = lp8788_backlight_register(bl); + if (ret) { + dev_err(lp->dev, "register backlight err: %d\n", ret); + goto err_dev; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &lp8788_attr_group); + if (ret) { + dev_err(lp->dev, "register sysfs err: %d\n", ret); + goto err_sysfs; + } + + backlight_update_status(bl->bl_dev); + + return 0; + +err_sysfs: + lp8788_backlight_unregister(bl); +err_dev: + return ret; +} + +static int lp8788_backlight_remove(struct platform_device *pdev) +{ + struct lp8788_bl *bl = platform_get_drvdata(pdev); + struct backlight_device *bl_dev = bl->bl_dev; + + bl_dev->props.brightness = 0; + backlight_update_status(bl_dev); + sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group); + lp8788_backlight_unregister(bl); + + return 0; +} + +static struct platform_driver lp8788_bl_driver = { + .probe = lp8788_backlight_probe, + .remove = lp8788_backlight_remove, + .driver = { + .name = LP8788_DEV_BACKLIGHT, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(lp8788_bl_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8788 Backlight Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-backlight"); diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index 6c0f1ac0d32..383f550e165 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -75,7 +75,7 @@ static int ltv350qv_power_on(struct ltv350qv *lcd) /* Power On Reset Display off State */ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000)) goto err; - msleep(15); + usleep_range(15000, 16000); /* Power Setting Function 1 */ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE)) @@ -153,7 +153,7 @@ err_settings: err_power2: err_power1: ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); - msleep(1); + usleep_range(1000, 1100); err: ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); return -EIO; @@ -175,7 +175,7 @@ static int ltv350qv_power_off(struct ltv350qv *lcd) ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); /* Wait at least 1 ms */ - msleep(1); + usleep_range(1000, 1100); /* Power down setting 2 */ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); @@ -226,7 +226,7 @@ static struct lcd_ops ltv_ops = { .set_power = ltv350qv_set_power, }; -static int __devinit ltv350qv_probe(struct spi_device *spi) +static int ltv350qv_probe(struct spi_device *spi) { struct ltv350qv *lcd; struct lcd_device *ld; @@ -242,7 +242,8 @@ static int __devinit ltv350qv_probe(struct spi_device *spi) if (!lcd->buffer) return -ENOMEM; - ld = lcd_device_register("ltv350qv", &spi->dev, lcd, <v_ops); + ld = devm_lcd_device_register(&spi->dev, "ltv350qv", &spi->dev, lcd, + <v_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -250,50 +251,43 @@ static int __devinit ltv350qv_probe(struct spi_device *spi) ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK); if (ret) - goto out_unregister; + return ret; - dev_set_drvdata(&spi->dev, lcd); + spi_set_drvdata(spi, lcd); return 0; - -out_unregister: - lcd_device_unregister(ld); - return ret; } -static int __devexit ltv350qv_remove(struct spi_device *spi) +static int ltv350qv_remove(struct spi_device *spi) { - struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + struct ltv350qv *lcd = spi_get_drvdata(spi); ltv350qv_power(lcd, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->ld); - return 0; } -#ifdef CONFIG_PM -static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int ltv350qv_suspend(struct device *dev) { - struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + struct ltv350qv *lcd = dev_get_drvdata(dev); return ltv350qv_power(lcd, FB_BLANK_POWERDOWN); } -static int ltv350qv_resume(struct spi_device *spi) +static int ltv350qv_resume(struct device *dev) { - struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + struct ltv350qv *lcd = dev_get_drvdata(dev); return ltv350qv_power(lcd, FB_BLANK_UNBLANK); } -#else -#define ltv350qv_suspend NULL -#define ltv350qv_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ltv350qv_pm_ops, ltv350qv_suspend, ltv350qv_resume); + /* Power down all displays on reboot, poweroff or halt */ static void ltv350qv_shutdown(struct spi_device *spi) { - struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + struct ltv350qv *lcd = spi_get_drvdata(spi); ltv350qv_power(lcd, FB_BLANK_POWERDOWN); } @@ -302,13 +296,12 @@ static struct spi_driver ltv350qv_driver = { .driver = { .name = "ltv350qv", .owner = THIS_MODULE, + .pm = <v350qv_pm_ops, }, .probe = ltv350qv_probe, - .remove = __devexit_p(ltv350qv_remove), + .remove = ltv350qv_remove, .shutdown = ltv350qv_shutdown, - .suspend = ltv350qv_suspend, - .resume = ltv350qv_resume, }; module_spi_driver(ltv350qv_driver); diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c new file mode 100644 index 00000000000..1802b2d1357 --- /dev/null +++ b/drivers/video/backlight/lv5207lp.c @@ -0,0 +1,170 @@ +/* + * Sanyo LV5207LP LED Driver + * + * Copyright (C) 2013 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/platform_data/lv5207lp.h> +#include <linux/slab.h> + +#define LV5207LP_CTRL1 0x00 +#define LV5207LP_CPSW (1 << 7) +#define LV5207LP_SCTEN (1 << 6) +#define LV5207LP_C10 (1 << 5) +#define LV5207LP_CKSW (1 << 4) +#define LV5207LP_RSW (1 << 3) +#define LV5207LP_GSW (1 << 2) +#define LV5207LP_BSW (1 << 1) +#define LV5207LP_CTRL2 0x01 +#define LV5207LP_MSW (1 << 7) +#define LV5207LP_MLED4 (1 << 6) +#define LV5207LP_RED 0x02 +#define LV5207LP_GREEN 0x03 +#define LV5207LP_BLUE 0x04 + +#define LV5207LP_MAX_BRIGHTNESS 32 + +struct lv5207lp { + struct i2c_client *client; + struct backlight_device *backlight; + struct lv5207lp_platform_data *pdata; +}; + +static int lv5207lp_write(struct lv5207lp *lv, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(lv->client, reg, data); +} + +static int lv5207lp_backlight_update_status(struct backlight_device *backlight) +{ + struct lv5207lp *lv = bl_get_data(backlight); + int brightness = backlight->props.brightness; + + if (backlight->props.power != FB_BLANK_UNBLANK || + backlight->props.fb_blank != FB_BLANK_UNBLANK || + backlight->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + if (brightness) { + lv5207lp_write(lv, LV5207LP_CTRL1, + LV5207LP_CPSW | LV5207LP_C10 | LV5207LP_CKSW); + lv5207lp_write(lv, LV5207LP_CTRL2, + LV5207LP_MSW | LV5207LP_MLED4 | + (brightness - 1)); + } else { + lv5207lp_write(lv, LV5207LP_CTRL1, 0); + lv5207lp_write(lv, LV5207LP_CTRL2, 0); + } + + return 0; +} + +static int lv5207lp_backlight_get_brightness(struct backlight_device *backlight) +{ + return backlight->props.brightness; +} + +static int lv5207lp_backlight_check_fb(struct backlight_device *backlight, + struct fb_info *info) +{ + struct lv5207lp *lv = bl_get_data(backlight); + + return lv->pdata->fbdev == NULL || lv->pdata->fbdev == info->dev; +} + +static const struct backlight_ops lv5207lp_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lv5207lp_backlight_update_status, + .get_brightness = lv5207lp_backlight_get_brightness, + .check_fb = lv5207lp_backlight_check_fb, +}; + +static int lv5207lp_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lv5207lp_platform_data *pdata = dev_get_platdata(&client->dev); + struct backlight_device *backlight; + struct backlight_properties props; + struct lv5207lp *lv; + + if (pdata == NULL) { + dev_err(&client->dev, "No platform data supplied\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&client->dev, + "I2C adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + lv = devm_kzalloc(&client->dev, sizeof(*lv), GFP_KERNEL); + if (!lv) + return -ENOMEM; + + lv->client = client; + lv->pdata = pdata; + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = min_t(unsigned int, pdata->max_value, + LV5207LP_MAX_BRIGHTNESS); + props.brightness = clamp_t(unsigned int, pdata->def_value, 0, + props.max_brightness); + + backlight = devm_backlight_device_register(&client->dev, + dev_name(&client->dev), &lv->client->dev, + lv, &lv5207lp_backlight_ops, &props); + if (IS_ERR(backlight)) { + dev_err(&client->dev, "failed to register backlight\n"); + return PTR_ERR(backlight); + } + + backlight_update_status(backlight); + i2c_set_clientdata(client, backlight); + + return 0; +} + +static int lv5207lp_remove(struct i2c_client *client) +{ + struct backlight_device *backlight = i2c_get_clientdata(client); + + backlight->props.brightness = 0; + backlight_update_status(backlight); + + return 0; +} + +static const struct i2c_device_id lv5207lp_ids[] = { + { "lv5207lp", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lv5207lp_ids); + +static struct i2c_driver lv5207lp_driver = { + .driver = { + .name = "lv5207lp", + }, + .probe = lv5207lp_probe, + .remove = lv5207lp_remove, + .id_table = lv5207lp_ids, +}; + +module_i2c_driver(lv5207lp_driver); + +MODULE_DESCRIPTION("Sanyo LV5207LP Backlight Driver"); +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index e833ac72e06..66fa08c920d 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; @@ -99,48 +101,70 @@ static const struct backlight_ops max8925_backlight_ops = { .get_brightness = max8925_backlight_get_brightness, }; -static int __devinit max8925_backlight_probe(struct platform_device *pdev) +static void max8925_backlight_dt_init(struct platform_device *pdev) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + struct max8925_backlight_pdata *pdata; + u32 val; + + if (!nproot || !IS_ENABLED(CONFIG_OF)) + return; + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct max8925_backlight_pdata), + GFP_KERNEL); + if (!pdata) + return; + + np = of_find_node_by_name(nproot, "backlight"); + if (!np) { + dev_err(&pdev->dev, "failed to find backlight node\n"); + return; + } + + if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val)) + pdata->dual_string = val; + + pdev->dev.platform_data = pdata; +} + +static int 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; 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_IO, 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"); + return -ENXIO; + } + 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"); + return -ENXIO; + } + 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 = devm_backlight_device_register(&pdev->dev, "max8925-backlight", + &pdev->dev, data, &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); @@ -151,29 +175,23 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) 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 (!pdev->dev.platform_data) + max8925_backlight_dt_init(pdev); + + pdata = pdev->dev.platform_data; + 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; - + return ret; backlight_update_status(bl); return 0; -out: - backlight_device_unregister(bl); - return ret; -} - -static int __devexit max8925_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; } static struct platform_driver max8925_backlight_driver = { @@ -182,7 +200,6 @@ static struct platform_driver max8925_backlight_driver = { .owner = THIS_MODULE, }, .probe = max8925_backlight_probe, - .remove = __devexit_p(max8925_backlight_remove), }; module_platform_driver(max8925_backlight_driver); diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index bfdc5fbeaa1..a0dcd88ac74 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -18,8 +18,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -27,10 +25,10 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/slab.h> +#include <linux/platform_data/omap1_bl.h> #include <mach/hardware.h> -#include <plat/board.h> -#include <plat/mux.h> +#include <mach/mux.h> #define OMAPBL_MAX_INTENSITY 0xff @@ -42,12 +40,12 @@ struct omap_backlight { struct omap_backlight_config *pdata; }; -static void inline omapbl_send_intensity(int intensity) +static inline void omapbl_send_intensity(int intensity) { omap_writeb(intensity, OMAP_PWL_ENABLE); } -static void inline omapbl_send_enable(int enable) +static inline void omapbl_send_enable(int enable) { omap_writeb(enable, OMAP_PWL_CLK_ENABLE); } @@ -73,32 +71,29 @@ static void omapbl_blank(struct omap_backlight *bl, int mode) } } -#ifdef CONFIG_PM -static int omapbl_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int omapbl_suspend(struct device *dev) { - struct backlight_device *dev = platform_get_drvdata(pdev); - struct omap_backlight *bl = dev_get_drvdata(&dev->dev); + struct backlight_device *bl_dev = dev_get_drvdata(dev); + struct omap_backlight *bl = bl_get_data(bl_dev); omapbl_blank(bl, FB_BLANK_POWERDOWN); return 0; } -static int omapbl_resume(struct platform_device *pdev) +static int omapbl_resume(struct device *dev) { - struct backlight_device *dev = platform_get_drvdata(pdev); - struct omap_backlight *bl = dev_get_drvdata(&dev->dev); + struct backlight_device *bl_dev = dev_get_drvdata(dev); + struct omap_backlight *bl = bl_get_data(bl_dev); omapbl_blank(bl, bl->powermode); return 0; } -#else -#define omapbl_suspend NULL -#define omapbl_resume NULL #endif static int omapbl_set_power(struct backlight_device *dev, int state) { - struct omap_backlight *bl = dev_get_drvdata(&dev->dev); + struct omap_backlight *bl = bl_get_data(dev); omapbl_blank(bl, state); bl->powermode = state; @@ -108,7 +103,7 @@ static int omapbl_set_power(struct backlight_device *dev, int state) static int omapbl_update_status(struct backlight_device *dev) { - struct omap_backlight *bl = dev_get_drvdata(&dev->dev); + struct omap_backlight *bl = bl_get_data(dev); if (bl->current_intensity != dev->props.brightness) { if (bl->powermode == FB_BLANK_UNBLANK) @@ -124,7 +119,7 @@ static int omapbl_update_status(struct backlight_device *dev) static int omapbl_get_intensity(struct backlight_device *dev) { - struct omap_backlight *bl = dev_get_drvdata(&dev->dev); + struct omap_backlight *bl = bl_get_data(dev); return bl->current_intensity; } @@ -138,7 +133,7 @@ static int omapbl_probe(struct platform_device *pdev) struct backlight_properties props; struct backlight_device *dev; struct omap_backlight *bl; - struct omap_backlight_config *pdata = pdev->dev.platform_data; + struct omap_backlight_config *pdata = dev_get_platdata(&pdev->dev); if (!pdata) return -ENXIO; @@ -151,8 +146,8 @@ static int omapbl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = OMAPBL_MAX_INTENSITY; - dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops, - &props); + dev = devm_backlight_device_register(&pdev->dev, "omap-bl", &pdev->dev, + bl, &omapbl_ops, &props); if (IS_ERR(dev)) return PTR_ERR(dev); @@ -170,27 +165,18 @@ static int omapbl_probe(struct platform_device *pdev) dev->props.brightness = pdata->default_intensity; omapbl_update_status(dev); - pr_info("OMAP LCD backlight initialised\n"); + dev_info(&pdev->dev, "OMAP LCD backlight initialised\n"); return 0; } -static int omapbl_remove(struct platform_device *pdev) -{ - struct backlight_device *dev = platform_get_drvdata(pdev); - - backlight_device_unregister(dev); - - return 0; -} +static SIMPLE_DEV_PM_OPS(omapbl_pm_ops, omapbl_suspend, omapbl_resume); static struct platform_driver omapbl_driver = { .probe = omapbl_probe, - .remove = omapbl_remove, - .suspend = omapbl_suspend, - .resume = omapbl_resume, .driver = { .name = "omap-bl", + .pm = &omapbl_pm_ops, }, }; diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c index f519d55a294..f5a5202dd79 100644 --- a/drivers/video/backlight/ot200_bl.c +++ b/drivers/video/backlight/ot200_bl.c @@ -14,6 +14,7 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/gpio.h> +#include <linux/platform_device.h> #include <linux/cs5535.h> static struct cs5535_mfgpt_timer *pwm_timer; @@ -84,7 +85,8 @@ static int ot200_backlight_probe(struct platform_device *pdev) int retval = 0; /* request gpio */ - if (gpio_request(GPIO_DIMM, "ot200 backlight dimmer") < 0) { + if (devm_gpio_request(&pdev->dev, GPIO_DIMM, + "ot200 backlight dimmer") < 0) { dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM); return -ENODEV; } @@ -93,14 +95,13 @@ static int ot200_backlight_probe(struct platform_device *pdev) pwm_timer = cs5535_mfgpt_alloc_timer(7, MFGPT_DOMAIN_ANY); if (!pwm_timer) { dev_err(&pdev->dev, "MFGPT 7 not available\n"); - retval = -ENODEV; - goto error_mfgpt_alloc; + return -ENODEV; } - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { retval = -ENOMEM; - goto error_kzalloc; + goto error_devm_kzalloc; } /* setup gpio */ @@ -117,34 +118,26 @@ static int ot200_backlight_probe(struct platform_device *pdev) props.brightness = 100; props.type = BACKLIGHT_RAW; - bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, data, - &ot200_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev), + &pdev->dev, data, &ot200_backlight_ops, + &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); retval = PTR_ERR(bl); - goto error_backlight_device_register; + goto error_devm_kzalloc; } platform_set_drvdata(pdev, bl); return 0; -error_backlight_device_register: - kfree(data); -error_kzalloc: +error_devm_kzalloc: cs5535_mfgpt_free_timer(pwm_timer); -error_mfgpt_alloc: - gpio_free(GPIO_DIMM); return retval; } static int ot200_backlight_remove(struct platform_device *pdev) { - struct backlight_device *bl = platform_get_drvdata(pdev); - struct ot200_backlight_data *data = bl_get_data(bl); - - backlight_device_unregister(bl); - /* on module unload set brightness to 100% */ cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0); cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN); @@ -152,9 +145,7 @@ static int ot200_backlight_remove(struct platform_device *pdev) MAX_COMP2 - dim_table[100]); cs5535_mfgpt_free_timer(pwm_timer); - gpio_free(GPIO_DIMM); - kfree(data); return 0; } diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c index 4ec30748b44..2098c5d6efb 100644 --- a/drivers/video/backlight/pandora_bl.c +++ b/drivers/video/backlight/pandora_bl.c @@ -71,8 +71,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl) * set PWM duty cycle to max. TPS61161 seems to use this * to calibrate it's PWM sensitivity when it starts. */ - twl_i2c_write_u8(TWL4030_MODULE_PWM0, MAX_VALUE, - TWL_PWM0_OFF); + twl_i2c_write_u8(TWL_MODULE_PWM, MAX_VALUE, TWL_PWM0_OFF); /* first enable clock, then PWM0 out */ twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1); @@ -90,8 +89,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl) usleep_range(2000, 10000); } - twl_i2c_write_u8(TWL4030_MODULE_PWM0, MIN_VALUE + brightness, - TWL_PWM0_OFF); + twl_i2c_write_u8(TWL_MODULE_PWM, MIN_VALUE + brightness, TWL_PWM0_OFF); done: if (brightness != 0) @@ -122,8 +120,8 @@ static int pandora_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.max_brightness = MAX_USER_VALUE; props.type = BACKLIGHT_RAW; - bl = backlight_device_register(pdev->name, &pdev->dev, - NULL, &pandora_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, + NULL, &pandora_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -132,7 +130,7 @@ static int pandora_backlight_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bl); /* 64 cycle period, ON position 0 */ - twl_i2c_write_u8(TWL4030_MODULE_PWM0, 0x80, TWL_PWM0_ON); + twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON); bl->props.state |= PANDORABL_WAS_OFF; bl->props.brightness = MAX_USER_VALUE; @@ -147,20 +145,12 @@ static int pandora_backlight_probe(struct platform_device *pdev) return 0; } -static int pandora_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - backlight_device_unregister(bl); - return 0; -} - static struct platform_driver pandora_backlight_driver = { .driver = { .name = "pandora-backlight", .owner = THIS_MODULE, }, .probe = pandora_backlight_probe, - .remove = pandora_backlight_remove, }; module_platform_driver(pandora_backlight_driver); diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index c092159f438..b95d3b0aaff 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -52,7 +52,7 @@ int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit) pcf_bl->brightness_limit = limit & 0x3f; backlight_update_status(pcf_bl->bl); - return 0; + return 0; } static int pcf50633_bl_update_status(struct backlight_device *bl) @@ -99,11 +99,11 @@ static const struct backlight_ops pcf50633_bl_ops = { .options = BL_CORE_SUSPENDRESUME, }; -static int __devinit pcf50633_bl_probe(struct platform_device *pdev) +static int pcf50633_bl_probe(struct platform_device *pdev) { struct pcf50633_bl *pcf_bl; struct device *parent = pdev->dev.parent; - struct pcf50633_platform_data *pcf50633_data = parent->platform_data; + struct pcf50633_platform_data *pcf50633_data = dev_get_platdata(parent); struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; struct backlight_properties bl_props; @@ -126,7 +126,8 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent); - pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, + pcf_bl->bl = devm_backlight_device_register(&pdev->dev, pdev->name, + &pdev->dev, pcf_bl, &pcf50633_bl_ops, &bl_props); if (IS_ERR(pcf_bl->bl)) @@ -136,8 +137,10 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time); - /* Should be different from bl_props.brightness, so we do not exit - * update_status early the first time it's called */ + /* + * Should be different from bl_props.brightness, so we do not exit + * update_status early the first time it's called + */ pcf_bl->brightness = pcf_bl->bl->props.brightness + 1; backlight_update_status(pcf_bl->bl); @@ -145,20 +148,8 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_bl_remove(struct platform_device *pdev) -{ - struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); - - backlight_device_unregister(pcf_bl->bl); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - static struct platform_driver pcf50633_bl_driver = { .probe = pcf50633_bl_probe, - .remove = __devexit_p(pcf50633_bl_remove), .driver = { .name = "pcf50633-backlight", }, diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index b6672340d6c..c3d2e209fc8 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -16,6 +16,7 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/lcd.h> +#include <linux/of.h> #include <linux/slab.h> #include <video/platform_lcd.h> @@ -26,7 +27,7 @@ struct platform_lcd { struct plat_lcd_data *pdata; unsigned int power; - unsigned int suspended : 1; + unsigned int suspended:1; }; static inline struct platform_lcd *to_our_lcd(struct lcd_device *lcd) @@ -72,55 +73,46 @@ static struct lcd_ops platform_lcd_ops = { .check_fb = platform_lcd_match, }; -static int __devinit platform_lcd_probe(struct platform_device *pdev) +static int platform_lcd_probe(struct platform_device *pdev) { struct plat_lcd_data *pdata; struct platform_lcd *plcd; struct device *dev = &pdev->dev; int err; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(dev, "no platform data supplied\n"); return -EINVAL; } + if (pdata->probe) { + err = pdata->probe(pdata); + if (err) + return err; + } + plcd = devm_kzalloc(&pdev->dev, sizeof(struct platform_lcd), GFP_KERNEL); - if (!plcd) { - dev_err(dev, "no memory for state\n"); + if (!plcd) return -ENOMEM; - } plcd->us = dev; plcd->pdata = pdata; - plcd->lcd = lcd_device_register(dev_name(dev), dev, - plcd, &platform_lcd_ops); + plcd->lcd = devm_lcd_device_register(&pdev->dev, dev_name(dev), dev, + plcd, &platform_lcd_ops); if (IS_ERR(plcd->lcd)) { dev_err(dev, "cannot register lcd device\n"); - err = PTR_ERR(plcd->lcd); - goto err; + return PTR_ERR(plcd->lcd); } platform_set_drvdata(pdev, plcd); platform_lcd_set_power(plcd->lcd, FB_BLANK_NORMAL); return 0; - - err: - return err; -} - -static int __devexit platform_lcd_remove(struct platform_device *pdev) -{ - struct platform_lcd *plcd = platform_get_drvdata(pdev); - - lcd_device_unregister(plcd->lcd); - - return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int platform_lcd_suspend(struct device *dev) { struct platform_lcd *plcd = dev_get_drvdata(dev); @@ -140,21 +132,27 @@ static int platform_lcd_resume(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend, platform_lcd_resume); + +#ifdef CONFIG_OF +static const struct of_device_id platform_lcd_of_match[] = { + { .compatible = "platform-lcd" }, + {}, +}; +MODULE_DEVICE_TABLE(of, platform_lcd_of_match); #endif static struct platform_driver platform_lcd_driver = { .driver = { .name = "platform-lcd", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &platform_lcd_pm_ops, -#endif + .of_match_table = of_match_ptr(platform_lcd_of_match), }, .probe = platform_lcd_probe, - .remove = __devexit_p(platform_lcd_remove), }; module_platform_driver(platform_lcd_driver); diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c deleted file mode 100644 index 69b35f02929..00000000000 --- a/drivers/video/backlight/progear_bl.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Backlight Driver for Frontpath ProGear HX1050+ - * - * Copyright (c) 2006 Marcin Juszkiewicz - * - * Based on Progear LCD driver by M Schacht - * <mschacht at alumni dot washington dot edu> - * - * Based on Sharp's Corgi Backlight Driver - * Based on Backlight Driver for HP Jornada 680 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/fb.h> -#include <linux/backlight.h> -#include <linux/pci.h> - -#define PMU_LPCR 0xB0 -#define SB_MPS1 0x61 -#define HW_LEVEL_MAX 0x77 -#define HW_LEVEL_MIN 0x4f - -static struct pci_dev *pmu_dev = NULL; -static struct pci_dev *sb_dev = NULL; - -static int progearbl_set_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (bd->props.power != FB_BLANK_UNBLANK) - intensity = 0; - if (bd->props.fb_blank != FB_BLANK_UNBLANK) - intensity = 0; - - pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN); - - return 0; -} - -static int progearbl_get_intensity(struct backlight_device *bd) -{ - u8 intensity; - pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity); - - return intensity - HW_LEVEL_MIN; -} - -static const struct backlight_ops progearbl_ops = { - .get_brightness = progearbl_get_intensity, - .update_status = progearbl_set_intensity, -}; - -static int progearbl_probe(struct platform_device *pdev) -{ - struct backlight_properties props; - u8 temp; - struct backlight_device *progear_backlight_device; - int ret; - - pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL); - if (!pmu_dev) { - pr_err("ALI M7101 PMU not found.\n"); - return -ENODEV; - } - - sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - if (!sb_dev) { - pr_err("ALI 1533 SB not found.\n"); - ret = -ENODEV; - goto put_pmu; - } - - /* Set SB_MPS1 to enable brightness control. */ - pci_read_config_byte(sb_dev, SB_MPS1, &temp); - pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20); - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progear_backlight_device = backlight_device_register("progear-bl", - &pdev->dev, NULL, - &progearbl_ops, - &props); - if (IS_ERR(progear_backlight_device)) { - ret = PTR_ERR(progear_backlight_device); - goto put_sb; - } - - platform_set_drvdata(pdev, progear_backlight_device); - - progear_backlight_device->props.power = FB_BLANK_UNBLANK; - progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progearbl_set_intensity(progear_backlight_device); - - return 0; -put_sb: - pci_dev_put(sb_dev); -put_pmu: - pci_dev_put(pmu_dev); - return ret; -} - -static int progearbl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - backlight_device_unregister(bd); - - return 0; -} - -static struct platform_driver progearbl_driver = { - .probe = progearbl_probe, - .remove = progearbl_remove, - .driver = { - .name = "progear-bl", - }, -}; - -static struct platform_device *progearbl_device; - -static int __init progearbl_init(void) -{ - int ret = platform_driver_register(&progearbl_driver); - - if (ret) - return ret; - progearbl_device = platform_device_register_simple("progear-bl", -1, - NULL, 0); - if (IS_ERR(progearbl_device)) { - platform_driver_unregister(&progearbl_driver); - return PTR_ERR(progearbl_device); - } - - return 0; -} - -static void __exit progearbl_exit(void) -{ - pci_dev_put(pmu_dev); - pci_dev_put(sb_dev); - - platform_device_unregister(progearbl_device); - platform_driver_unregister(&progearbl_driver); -} - -module_init(progearbl_init); -module_exit(progearbl_exit); - -MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>"); -MODULE_DESCRIPTION("ProGear Backlight Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 342b7d7cbb6..38ca88bc5c3 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -10,6 +10,8 @@ * published by the Free Software Foundation. */ +#include <linux/gpio/consumer.h> +#include <linux/gpio.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -19,6 +21,7 @@ #include <linux/err.h> #include <linux/pwm.h> #include <linux/pwm_backlight.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> struct pwm_bl_data { @@ -26,37 +29,85 @@ struct pwm_bl_data { struct device *dev; unsigned int period; unsigned int lth_brightness; + unsigned int *levels; + bool enabled; + struct regulator *power_supply; + struct gpio_desc *enable_gpio; + unsigned int scale; int (*notify)(struct device *, int brightness); void (*notify_after)(struct device *, int brightness); int (*check_fb)(struct device *, struct fb_info *); + void (*exit)(struct device *); }; +static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) +{ + int err; + + if (pb->enabled) + return; + + err = regulator_enable(pb->power_supply); + if (err < 0) + dev_err(pb->dev, "failed to enable power supply\n"); + + if (pb->enable_gpio) + gpiod_set_value(pb->enable_gpio, 1); + + pwm_enable(pb->pwm); + pb->enabled = true; +} + +static void pwm_backlight_power_off(struct pwm_bl_data *pb) +{ + if (!pb->enabled) + return; + + pwm_config(pb->pwm, 0, pb->period); + pwm_disable(pb->pwm); + + if (pb->enable_gpio) + gpiod_set_value(pb->enable_gpio, 0); + + regulator_disable(pb->power_supply); + pb->enabled = false; +} + +static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) +{ + unsigned int lth = pb->lth_brightness; + int duty_cycle; + + if (pb->levels) + duty_cycle = pb->levels[brightness]; + else + duty_cycle = brightness; + + return (duty_cycle * (pb->period - lth) / pb->scale) + lth; +} + static int pwm_backlight_update_status(struct backlight_device *bl) { - struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); + struct pwm_bl_data *pb = bl_get_data(bl); int brightness = bl->props.brightness; - int max = bl->props.max_brightness; - - if (bl->props.power != FB_BLANK_UNBLANK) - brightness = 0; + int duty_cycle; - if (bl->props.fb_blank != FB_BLANK_UNBLANK) + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & BL_CORE_FBBLANK) brightness = 0; if (pb->notify) brightness = pb->notify(pb->dev, brightness); - if (brightness == 0) { - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); - } else { - brightness = pb->lth_brightness + - (brightness * (pb->period - pb->lth_brightness) / max); - pwm_config(pb->pwm, brightness, pb->period); - pwm_enable(pb->pwm); - } + if (brightness > 0) { + duty_cycle = compute_duty_cycle(pb, brightness); + pwm_config(pb->pwm, duty_cycle, pb->period); + pwm_backlight_power_on(pb, brightness); + } else + pwm_backlight_power_off(pb); if (pb->notify_after) pb->notify_after(pb->dev, brightness); @@ -72,7 +123,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl) static int pwm_backlight_check_fb(struct backlight_device *bl, struct fb_info *info) { - struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); + struct pwm_bl_data *pb = bl_get_data(bl); return !pb->check_fb || pb->check_fb(pb->dev, info); } @@ -83,17 +134,85 @@ static const struct backlight_ops pwm_backlight_ops = { .check_fb = pwm_backlight_check_fb, }; +#ifdef CONFIG_OF +static int pwm_backlight_parse_dt(struct device *dev, + struct platform_pwm_backlight_data *data) +{ + struct device_node *node = dev->of_node; + struct property *prop; + int length; + u32 value; + int ret; + + if (!node) + return -ENODEV; + + memset(data, 0, sizeof(*data)); + + /* determine the number of brightness levels */ + prop = of_find_property(node, "brightness-levels", &length); + if (!prop) + return -EINVAL; + + data->max_brightness = length / sizeof(u32); + + /* read brightness levels from DT property */ + if (data->max_brightness > 0) { + size_t size = sizeof(*data->levels) * data->max_brightness; + + data->levels = devm_kzalloc(dev, size, GFP_KERNEL); + if (!data->levels) + return -ENOMEM; + + ret = of_property_read_u32_array(node, "brightness-levels", + data->levels, + data->max_brightness); + if (ret < 0) + return ret; + + ret = of_property_read_u32(node, "default-brightness-level", + &value); + if (ret < 0) + return ret; + + data->dft_brightness = value; + data->max_brightness--; + } + + return 0; +} + +static struct of_device_id pwm_backlight_of_match[] = { + { .compatible = "pwm-backlight" }, + { } +}; + +MODULE_DEVICE_TABLE(of, pwm_backlight_of_match); +#else +static int pwm_backlight_parse_dt(struct device *dev, + struct platform_pwm_backlight_data *data) +{ + return -ENODEV; +} +#endif + static int pwm_backlight_probe(struct platform_device *pdev) { + struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev); + struct platform_pwm_backlight_data defdata; struct backlight_properties props; - struct platform_pwm_backlight_data *data = pdev->dev.platform_data; struct backlight_device *bl; struct pwm_bl_data *pb; int ret; if (!data) { - dev_err(&pdev->dev, "failed to find platform data\n"); - return -EINVAL; + ret = pwm_backlight_parse_dt(&pdev->dev, &defdata); + if (ret < 0) { + dev_err(&pdev->dev, "failed to find platform data\n"); + return ret; + } + + data = &defdata; } if (data->init) { @@ -104,26 +223,89 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL); if (!pb) { - dev_err(&pdev->dev, "no memory for state\n"); ret = -ENOMEM; goto err_alloc; } - pb->period = data->pwm_period_ns; + if (data->levels) { + unsigned int i; + + for (i = 0; i <= data->max_brightness; i++) + if (data->levels[i] > pb->scale) + pb->scale = data->levels[i]; + + pb->levels = data->levels; + } else + pb->scale = data->max_brightness; + pb->notify = data->notify; pb->notify_after = data->notify_after; pb->check_fb = data->check_fb; - pb->lth_brightness = data->lth_brightness * - (data->pwm_period_ns / data->max_brightness); + pb->exit = data->exit; pb->dev = &pdev->dev; + pb->enabled = false; + + pb->enable_gpio = devm_gpiod_get(&pdev->dev, "enable"); + if (IS_ERR(pb->enable_gpio)) { + ret = PTR_ERR(pb->enable_gpio); + if (ret == -ENOENT) + pb->enable_gpio = NULL; + else + goto err_alloc; + } - pb->pwm = pwm_request(data->pwm_id, "backlight"); - if (IS_ERR(pb->pwm)) { - dev_err(&pdev->dev, "unable to request PWM for backlight\n"); - ret = PTR_ERR(pb->pwm); + /* + * Compatibility fallback for drivers still using the integer GPIO + * platform data. Must go away soon. + */ + if (!pb->enable_gpio && gpio_is_valid(data->enable_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, data->enable_gpio, + GPIOF_OUT_INIT_HIGH, "enable"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n", + data->enable_gpio, ret); + goto err_alloc; + } + + pb->enable_gpio = gpio_to_desc(data->enable_gpio); + } + + if (pb->enable_gpio) + gpiod_direction_output(pb->enable_gpio, 1); + + pb->power_supply = devm_regulator_get(&pdev->dev, "power"); + if (IS_ERR(pb->power_supply)) { + ret = PTR_ERR(pb->power_supply); goto err_alloc; - } else - dev_dbg(&pdev->dev, "got pwm for backlight\n"); + } + + pb->pwm = devm_pwm_get(&pdev->dev, NULL); + if (IS_ERR(pb->pwm)) { + dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); + + pb->pwm = pwm_request(data->pwm_id, "pwm-backlight"); + if (IS_ERR(pb->pwm)) { + dev_err(&pdev->dev, "unable to request legacy PWM\n"); + ret = PTR_ERR(pb->pwm); + goto err_alloc; + } + } + + dev_dbg(&pdev->dev, "got pwm for backlight\n"); + + /* + * The DT case will set the pwm_period_ns field to 0 and store the + * period, parsed from the DT, in the PWM device. For the non-DT case, + * set the period from platform data if it has not already been set + * via the PWM lookup table. + */ + pb->period = pwm_get_period(pb->pwm); + if (!pb->period && (data->pwm_period_ns > 0)) { + pb->period = data->pwm_period_ns; + pwm_set_period(pb->pwm, data->pwm_period_ns); + } + + pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale); memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; @@ -133,7 +315,14 @@ static int pwm_backlight_probe(struct platform_device *pdev) if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); ret = PTR_ERR(bl); - goto err_bl; + goto err_alloc; + } + + if (data->dft_brightness > data->max_brightness) { + dev_warn(&pdev->dev, + "invalid default brightness level: %u, using %u\n", + data->dft_brightness, data->max_brightness); + data->dft_brightness = data->max_brightness; } bl->props.brightness = data->dft_brightness; @@ -142,8 +331,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bl); return 0; -err_bl: - pwm_free(pb->pwm); err_alloc: if (data->exit) data->exit(&pdev->dev); @@ -152,31 +339,40 @@ err_alloc: static int pwm_backlight_remove(struct platform_device *pdev) { - struct platform_pwm_backlight_data *data = pdev->dev.platform_data; struct backlight_device *bl = platform_get_drvdata(pdev); - struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); + struct pwm_bl_data *pb = bl_get_data(bl); backlight_device_unregister(bl); - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); - pwm_free(pb->pwm); - if (data->exit) - data->exit(&pdev->dev); + pwm_backlight_power_off(pb); + + if (pb->exit) + pb->exit(&pdev->dev); + return 0; } -#ifdef CONFIG_PM +static void pwm_backlight_shutdown(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct pwm_bl_data *pb = bl_get_data(bl); + + pwm_backlight_power_off(pb); +} + +#ifdef CONFIG_PM_SLEEP static int pwm_backlight_suspend(struct device *dev) { struct backlight_device *bl = dev_get_drvdata(dev); - struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); + struct pwm_bl_data *pb = bl_get_data(bl); if (pb->notify) pb->notify(pb->dev, 0); - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); + + pwm_backlight_power_off(pb); + if (pb->notify_after) pb->notify_after(pb->dev, 0); + return 0; } @@ -185,24 +381,30 @@ static int pwm_backlight_resume(struct device *dev) struct backlight_device *bl = dev_get_drvdata(dev); backlight_update_status(bl); + return 0; } +#endif -static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend, - pwm_backlight_resume); - +static const struct dev_pm_ops pwm_backlight_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pwm_backlight_suspend, + .resume = pwm_backlight_resume, + .poweroff = pwm_backlight_suspend, + .restore = pwm_backlight_resume, #endif +}; static struct platform_driver pwm_backlight_driver = { .driver = { - .name = "pwm-backlight", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &pwm_backlight_pm_ops, -#endif + .name = "pwm-backlight", + .owner = THIS_MODULE, + .pm = &pwm_backlight_pm_ops, + .of_match_table = of_match_ptr(pwm_backlight_of_match), }, .probe = pwm_backlight_probe, .remove = pwm_backlight_remove, + .shutdown = pwm_backlight_shutdown, }; module_platform_driver(pwm_backlight_driver); @@ -210,4 +412,3 @@ module_platform_driver(pwm_backlight_driver); MODULE_DESCRIPTION("PWM based Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pwm-backlight"); - diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 6437ae474cf..2d6d48196c6 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -9,28 +9,19 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <linux/wait.h> -#include <linux/fb.h> +#include <linux/backlight.h> #include <linux/delay.h> +#include <linux/fb.h> #include <linux/gpio.h> -#include <linux/spi/spi.h> -#include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/lcd.h> -#include <linux/backlight.h> #include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/wait.h> #include "s6e63m0_gamma.h" @@ -43,8 +34,6 @@ #define MIN_BRIGHTNESS 0 #define MAX_BRIGHTNESS 10 -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) - struct s6e63m0 { struct device *dev; struct spi_device *spi; @@ -57,7 +46,7 @@ struct s6e63m0 { struct lcd_platform_data *lcd_pd; }; -static const unsigned short SEQ_PANEL_CONDITION_SET[] = { +static const unsigned short seq_panel_condition_set[] = { 0xF8, 0x01, DATA_ONLY, 0x27, DATA_ONLY, 0x27, @@ -76,7 +65,7 @@ static const unsigned short SEQ_PANEL_CONDITION_SET[] = { ENDDEF, 0x0000 }; -static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { +static const unsigned short seq_display_condition_set[] = { 0xf2, 0x02, DATA_ONLY, 0x03, DATA_ONLY, 0x1c, @@ -90,7 +79,7 @@ static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { ENDDEF, 0x0000 }; -static const unsigned short SEQ_GAMMA_SETTING[] = { +static const unsigned short seq_gamma_setting[] = { 0xfa, 0x00, DATA_ONLY, 0x18, DATA_ONLY, 0x08, @@ -119,7 +108,7 @@ static const unsigned short SEQ_GAMMA_SETTING[] = { ENDDEF, 0x0000 }; -static const unsigned short SEQ_ETC_CONDITION_SET[] = { +static const unsigned short seq_etc_condition_set[] = { 0xf6, 0x00, DATA_ONLY, 0x8c, DATA_ONLY, 0x07, @@ -318,47 +307,47 @@ static const unsigned short SEQ_ETC_CONDITION_SET[] = { ENDDEF, 0x0000 }; -static const unsigned short SEQ_ACL_ON[] = { +static const unsigned short seq_acl_on[] = { /* ACL on */ 0xc0, 0x01, ENDDEF, 0x0000 }; -static const unsigned short SEQ_ACL_OFF[] = { +static const unsigned short seq_acl_off[] = { /* ACL off */ 0xc0, 0x00, ENDDEF, 0x0000 }; -static const unsigned short SEQ_ELVSS_ON[] = { +static const unsigned short seq_elvss_on[] = { /* ELVSS on */ 0xb1, 0x0b, ENDDEF, 0x0000 }; -static const unsigned short SEQ_ELVSS_OFF[] = { +static const unsigned short seq_elvss_off[] = { /* ELVSS off */ 0xb1, 0x0a, ENDDEF, 0x0000 }; -static const unsigned short SEQ_STAND_BY_OFF[] = { +static const unsigned short seq_stand_by_off[] = { 0x11, COMMAND_ONLY, ENDDEF, 0x0000 }; -static const unsigned short SEQ_STAND_BY_ON[] = { +static const unsigned short seq_stand_by_on[] = { 0x10, COMMAND_ONLY, ENDDEF, 0x0000 }; -static const unsigned short SEQ_DISPLAY_ON[] = { +static const unsigned short seq_display_on[] = { 0x29, COMMAND_ONLY, ENDDEF, 0x0000 @@ -406,8 +395,9 @@ static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd, ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]); if (ret) break; - } else - udelay(wbuf[i+1]*1000); + } else { + msleep(wbuf[i+1]); + } i += 2; } @@ -457,12 +447,12 @@ static int s6e63m0_ldi_init(struct s6e63m0 *lcd) { int ret, i; const unsigned short *init_seq[] = { - SEQ_PANEL_CONDITION_SET, - SEQ_DISPLAY_CONDITION_SET, - SEQ_GAMMA_SETTING, - SEQ_ETC_CONDITION_SET, - SEQ_ACL_ON, - SEQ_ELVSS_ON, + seq_panel_condition_set, + seq_display_condition_set, + seq_gamma_setting, + seq_etc_condition_set, + seq_acl_on, + seq_elvss_on, }; for (i = 0; i < ARRAY_SIZE(init_seq); i++) { @@ -478,8 +468,8 @@ static int s6e63m0_ldi_enable(struct s6e63m0 *lcd) { int ret = 0, i; const unsigned short *enable_seq[] = { - SEQ_STAND_BY_OFF, - SEQ_DISPLAY_ON, + seq_stand_by_off, + seq_display_on, }; for (i = 0; i < ARRAY_SIZE(enable_seq); i++) { @@ -495,43 +485,39 @@ static int s6e63m0_ldi_disable(struct s6e63m0 *lcd) { int ret; - ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON); + ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on); return ret; } +static int s6e63m0_power_is_on(int power) +{ + return power <= FB_BLANK_NORMAL; +} + static int s6e63m0_power_on(struct s6e63m0 *lcd) { int ret = 0; - struct lcd_platform_data *pd = NULL; - struct backlight_device *bd = NULL; + struct lcd_platform_data *pd; + struct backlight_device *bd; pd = lcd->lcd_pd; - if (!pd) { - dev_err(lcd->dev, "platform data is NULL.\n"); - return -EFAULT; - } - bd = lcd->bd; - if (!bd) { - dev_err(lcd->dev, "backlight device is NULL.\n"); - return -EFAULT; - } if (!pd->power_on) { dev_err(lcd->dev, "power_on is NULL.\n"); - return -EFAULT; + return -EINVAL; } else { pd->power_on(lcd->ld, 1); - mdelay(pd->power_on_delay); + msleep(pd->power_on_delay); } if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); - return -EFAULT; + return -EINVAL; } else { pd->reset(lcd->ld); - mdelay(pd->reset_delay); + msleep(pd->reset_delay); } ret = s6e63m0_ldi_init(lcd); @@ -558,14 +544,10 @@ static int s6e63m0_power_on(struct s6e63m0 *lcd) static int s6e63m0_power_off(struct s6e63m0 *lcd) { - int ret = 0; - struct lcd_platform_data *pd = NULL; + int ret; + struct lcd_platform_data *pd; pd = lcd->lcd_pd; - if (!pd) { - dev_err(lcd->dev, "platform data is NULL.\n"); - return -EFAULT; - } ret = s6e63m0_ldi_disable(lcd); if (ret) { @@ -573,13 +555,9 @@ static int s6e63m0_power_off(struct s6e63m0 *lcd) return -EIO; } - mdelay(pd->power_off_delay); + msleep(pd->power_off_delay); - if (!pd->power_on) { - dev_err(lcd->dev, "power_on is NULL.\n"); - return -EFAULT; - } else - pd->power_on(lcd->ld, 0); + pd->power_on(lcd->ld, 0); return 0; } @@ -588,9 +566,9 @@ static int s6e63m0_power(struct s6e63m0 *lcd, int power) { int ret = 0; - if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + if (s6e63m0_power_is_on(power) && !s6e63m0_power_is_on(lcd->power)) ret = s6e63m0_power_on(lcd); - else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + else if (!s6e63m0_power_is_on(power) && s6e63m0_power_is_on(lcd->power)) ret = s6e63m0_power_off(lcd); if (!ret) @@ -725,7 +703,7 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, struct s6e63m0 *lcd = dev_get_drvdata(dev); char temp[3]; - sprintf(temp, "%d\n", lcd->gamma_table_count); + sprintf(temp, "%u\n", lcd->gamma_table_count); strcpy(buf, temp); return strlen(buf); @@ -733,7 +711,7 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, static DEVICE_ATTR(gamma_table, 0444, s6e63m0_sysfs_show_gamma_table, NULL); -static int __devinit s6e63m0_probe(struct spi_device *spi) +static int s6e63m0_probe(struct spi_device *spi) { int ret = 0; struct s6e63m0 *lcd = NULL; @@ -757,13 +735,14 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL.\n"); - return -EFAULT; + return -EINVAL; } - ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops); + ld = devm_lcd_device_register(&spi->dev, "s6e63m0", &spi->dev, lcd, + &s6e63m0_lcd_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -773,12 +752,11 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, - &s6e63m0_backlight_ops, &props); - if (IS_ERR(bd)) { - ret = PTR_ERR(bd); - goto out_lcd_unregister; - } + bd = devm_backlight_device_register(&spi->dev, "s6e63m0bl-bl", + &spi->dev, lcd, &s6e63m0_backlight_ops, + &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); bd->props.brightness = MAX_BRIGHTNESS; lcd->bd = bd; @@ -788,7 +766,7 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) * know that. */ lcd->gamma_table_count = - sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int)); + sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int *)); ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode); if (ret < 0) @@ -811,82 +789,58 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) lcd->power = FB_BLANK_POWERDOWN; s6e63m0_power(lcd, FB_BLANK_UNBLANK); - } else + } else { lcd->power = FB_BLANK_UNBLANK; + } - dev_set_drvdata(&spi->dev, lcd); + spi_set_drvdata(spi, lcd); dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); return 0; - -out_lcd_unregister: - lcd_device_unregister(ld); - return ret; } -static int __devexit s6e63m0_remove(struct spi_device *spi) +static int s6e63m0_remove(struct spi_device *spi) { - struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + struct s6e63m0 *lcd = spi_get_drvdata(spi); s6e63m0_power(lcd, FB_BLANK_POWERDOWN); device_remove_file(&spi->dev, &dev_attr_gamma_table); device_remove_file(&spi->dev, &dev_attr_gamma_mode); - backlight_device_unregister(lcd->bd); - lcd_device_unregister(lcd->ld); return 0; } -#if defined(CONFIG_PM) -static unsigned int before_power; - -static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int s6e63m0_suspend(struct device *dev) { - int ret = 0; - struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); - - dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + struct s6e63m0 *lcd = dev_get_drvdata(dev); - before_power = lcd->power; + dev_dbg(dev, "lcd->power = %d\n", lcd->power); /* * when lcd panel is suspend, lcd panel becomes off * regardless of status. */ - ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN); - - return ret; + return s6e63m0_power(lcd, FB_BLANK_POWERDOWN); } -static int s6e63m0_resume(struct spi_device *spi) +static int s6e63m0_resume(struct device *dev) { - int ret = 0; - struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); - - /* - * after suspended, if lcd panel status is FB_BLANK_UNBLANK - * (at that time, before_power is FB_BLANK_UNBLANK) then - * it changes that status to FB_BLANK_POWERDOWN to get lcd on. - */ - if (before_power == FB_BLANK_UNBLANK) - lcd->power = FB_BLANK_POWERDOWN; - - dev_dbg(&spi->dev, "before_power = %d\n", before_power); + struct s6e63m0 *lcd = dev_get_drvdata(dev); - ret = s6e63m0_power(lcd, before_power); + lcd->power = FB_BLANK_POWERDOWN; - return ret; + return s6e63m0_power(lcd, FB_BLANK_UNBLANK); } -#else -#define s6e63m0_suspend NULL -#define s6e63m0_resume NULL #endif +static SIMPLE_DEV_PM_OPS(s6e63m0_pm_ops, s6e63m0_suspend, s6e63m0_resume); + /* Power down all displays on reboot, poweroff or halt. */ static void s6e63m0_shutdown(struct spi_device *spi) { - struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); + struct s6e63m0 *lcd = spi_get_drvdata(spi); s6e63m0_power(lcd, FB_BLANK_POWERDOWN); } @@ -895,12 +849,11 @@ static struct spi_driver s6e63m0_driver = { .driver = { .name = "s6e63m0", .owner = THIS_MODULE, + .pm = &s6e63m0_pm_ops, }, .probe = s6e63m0_probe, - .remove = __devexit_p(s6e63m0_remove), + .remove = s6e63m0_remove, .shutdown = s6e63m0_shutdown, - .suspend = s6e63m0_suspend, - .resume = s6e63m0_resume, }; module_spi_driver(s6e63m0_driver); diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 02444d042cd..908016fc582 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -2,7 +2,7 @@ * tdo24m - SPI-based drivers for Toppoly TDO24M series LCD panels * * Copyright (C) 2008 Marvell International Ltd. - * Eric Miao <eric.miao@marvell.com> + * Eric Miao <eric.miao@marvell.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -47,7 +47,7 @@ struct tdo24m { ((x1) << 9) | 0x100 | (x2)) #define CMD_NULL (-1) -static uint32_t lcd_panel_reset[] = { +static const uint32_t lcd_panel_reset[] = { CMD0(0x1), /* reset */ CMD0(0x0), /* nop */ CMD0(0x0), /* nop */ @@ -55,7 +55,7 @@ static uint32_t lcd_panel_reset[] = { CMD_NULL, }; -static uint32_t lcd_panel_on[] = { +static const uint32_t lcd_panel_on[] = { CMD0(0x29), /* Display ON */ CMD2(0xB8, 0xFF, 0xF9), /* Output Control */ CMD0(0x11), /* Sleep out */ @@ -63,7 +63,7 @@ static uint32_t lcd_panel_on[] = { CMD_NULL, }; -static uint32_t lcd_panel_off[] = { +static const uint32_t lcd_panel_off[] = { CMD0(0x28), /* Display OFF */ CMD2(0xB8, 0x80, 0x02), /* Output Control */ CMD0(0x10), /* Sleep in */ @@ -71,7 +71,7 @@ static uint32_t lcd_panel_off[] = { CMD_NULL, }; -static uint32_t lcd_vga_pass_through_tdo24m[] = { +static const uint32_t lcd_vga_pass_through_tdo24m[] = { CMD1(0xB0, 0x16), CMD1(0xBC, 0x80), CMD1(0xE1, 0x00), @@ -80,7 +80,7 @@ static uint32_t lcd_vga_pass_through_tdo24m[] = { CMD_NULL, }; -static uint32_t lcd_qvga_pass_through_tdo24m[] = { +static const uint32_t lcd_qvga_pass_through_tdo24m[] = { CMD1(0xB0, 0x16), CMD1(0xBC, 0x81), CMD1(0xE1, 0x00), @@ -89,8 +89,8 @@ static uint32_t lcd_qvga_pass_through_tdo24m[] = { CMD_NULL, }; -static uint32_t lcd_vga_transfer_tdo24m[] = { - CMD1(0xcf, 0x02), /* Blanking period control (1) */ +static const uint32_t lcd_vga_transfer_tdo24m[] = { + CMD1(0xcf, 0x02), /* Blanking period control (1) */ CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */ CMD1(0xd1, 0x01), /* CKV timing control on/off */ CMD2(0xd2, 0x14, 0x00), /* CKV 1,2 timing control */ @@ -102,7 +102,7 @@ static uint32_t lcd_vga_transfer_tdo24m[] = { CMD_NULL, }; -static uint32_t lcd_qvga_transfer[] = { +static const uint32_t lcd_qvga_transfer[] = { CMD1(0xd6, 0x02), /* Blanking period control (1) */ CMD2(0xd7, 0x08, 0x04), /* Blanking period control (2) */ CMD1(0xd8, 0x01), /* CKV timing control on/off */ @@ -115,7 +115,7 @@ static uint32_t lcd_qvga_transfer[] = { CMD_NULL, }; -static uint32_t lcd_vga_pass_through_tdo35s[] = { +static const uint32_t lcd_vga_pass_through_tdo35s[] = { CMD1(0xB0, 0x16), CMD1(0xBC, 0x80), CMD1(0xE1, 0x00), @@ -123,7 +123,7 @@ static uint32_t lcd_vga_pass_through_tdo35s[] = { CMD_NULL, }; -static uint32_t lcd_qvga_pass_through_tdo35s[] = { +static const uint32_t lcd_qvga_pass_through_tdo35s[] = { CMD1(0xB0, 0x16), CMD1(0xBC, 0x81), CMD1(0xE1, 0x00), @@ -131,8 +131,8 @@ static uint32_t lcd_qvga_pass_through_tdo35s[] = { CMD_NULL, }; -static uint32_t lcd_vga_transfer_tdo35s[] = { - CMD1(0xcf, 0x02), /* Blanking period control (1) */ +static const uint32_t lcd_vga_transfer_tdo35s[] = { + CMD1(0xcf, 0x02), /* Blanking period control (1) */ CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */ CMD1(0xd1, 0x01), /* CKV timing control on/off */ CMD2(0xd2, 0x00, 0x1e), /* CKV 1,2 timing control */ @@ -144,7 +144,7 @@ static uint32_t lcd_vga_transfer_tdo35s[] = { CMD_NULL, }; -static uint32_t lcd_panel_config[] = { +static const uint32_t lcd_panel_config[] = { CMD2(0xb8, 0xff, 0xf9), /* Output control */ CMD0(0x11), /* sleep out */ CMD1(0xba, 0x01), /* Display mode (1) */ @@ -175,10 +175,11 @@ static uint32_t lcd_panel_config[] = { CMD_NULL, }; -static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array) +static int tdo24m_writes(struct tdo24m *lcd, const uint32_t *array) { struct spi_transfer *x = &lcd->xfer; - uint32_t data, *p = array; + const uint32_t *p = array; + uint32_t data; int nparams, err = 0; for (; *p != CMD_NULL; p++) { @@ -328,7 +329,7 @@ static struct lcd_ops tdo24m_ops = { .set_mode = tdo24m_set_mode, }; -static int __devinit tdo24m_probe(struct spi_device *spi) +static int tdo24m_probe(struct spi_device *spi) { struct tdo24m *lcd; struct spi_message *m; @@ -337,7 +338,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi) enum tdo24m_model model; int err; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (pdata) model = pdata->model; else @@ -384,56 +385,49 @@ static int __devinit tdo24m_probe(struct spi_device *spi) return -EINVAL; } - lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev, - lcd, &tdo24m_ops); + lcd->lcd_dev = devm_lcd_device_register(&spi->dev, "tdo24m", &spi->dev, + lcd, &tdo24m_ops); if (IS_ERR(lcd->lcd_dev)) return PTR_ERR(lcd->lcd_dev); - dev_set_drvdata(&spi->dev, lcd); + spi_set_drvdata(spi, lcd); err = tdo24m_power(lcd, FB_BLANK_UNBLANK); if (err) - goto out_unregister; + return err; return 0; - -out_unregister: - lcd_device_unregister(lcd->lcd_dev); - return err; } -static int __devexit tdo24m_remove(struct spi_device *spi) +static int tdo24m_remove(struct spi_device *spi) { - struct tdo24m *lcd = dev_get_drvdata(&spi->dev); + struct tdo24m *lcd = spi_get_drvdata(spi); tdo24m_power(lcd, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->lcd_dev); - return 0; } -#ifdef CONFIG_PM -static int tdo24m_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int tdo24m_suspend(struct device *dev) { - struct tdo24m *lcd = dev_get_drvdata(&spi->dev); + struct tdo24m *lcd = dev_get_drvdata(dev); return tdo24m_power(lcd, FB_BLANK_POWERDOWN); } -static int tdo24m_resume(struct spi_device *spi) +static int tdo24m_resume(struct device *dev) { - struct tdo24m *lcd = dev_get_drvdata(&spi->dev); + struct tdo24m *lcd = dev_get_drvdata(dev); return tdo24m_power(lcd, FB_BLANK_UNBLANK); } -#else -#define tdo24m_suspend NULL -#define tdo24m_resume NULL #endif +static SIMPLE_DEV_PM_OPS(tdo24m_pm_ops, tdo24m_suspend, tdo24m_resume); + /* Power down all displays on reboot, poweroff or halt */ static void tdo24m_shutdown(struct spi_device *spi) { - struct tdo24m *lcd = dev_get_drvdata(&spi->dev); + struct tdo24m *lcd = spi_get_drvdata(spi); tdo24m_power(lcd, FB_BLANK_POWERDOWN); } @@ -442,12 +436,11 @@ static struct spi_driver tdo24m_driver = { .driver = { .name = "tdo24m", .owner = THIS_MODULE, + .pm = &tdo24m_pm_ops, }, .probe = tdo24m_probe, - .remove = __devexit_p(tdo24m_remove), + .remove = tdo24m_remove, .shutdown = tdo24m_shutdown, - .suspend = tdo24m_suspend, - .resume = tdo24m_resume, }; module_spi_driver(tdo24m_driver); diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 0d54e607e82..3ad676558c8 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -38,7 +38,7 @@ struct tosa_bl_data { static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness) { - struct spi_device *spi = data->i2c->dev.platform_data; + struct spi_device *spi = dev_get_platdata(&data->i2c->dev); i2c_smbus_write_byte_data(data->i2c, DAC_CH1, data->comadj); @@ -54,7 +54,7 @@ static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness) static int tosa_bl_update_status(struct backlight_device *dev) { struct backlight_properties *props = &dev->props; - struct tosa_bl_data *data = dev_get_drvdata(&dev->dev); + struct tosa_bl_data *data = bl_get_data(dev); int power = max(props->power, props->fb_blank); int brightness = props->brightness; @@ -78,7 +78,7 @@ static const struct backlight_ops bl_ops = { .update_status = tosa_bl_update_status, }; -static int __devinit tosa_bl_probe(struct i2c_client *client, +static int tosa_bl_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct backlight_properties props; @@ -92,14 +92,12 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj; - ret = gpio_request(TOSA_GPIO_BL_C20MA, "backlight"); + ret = devm_gpio_request_one(&client->dev, TOSA_GPIO_BL_C20MA, + GPIOF_OUT_INIT_LOW, "backlight"); if (ret) { dev_dbg(&data->bl->dev, "Unable to request gpio!\n"); return ret; } - ret = gpio_direction_output(TOSA_GPIO_BL_C20MA, 0); - if (ret) - goto err_gpio_dir; i2c_set_clientdata(client, data); data->i2c = client; @@ -107,8 +105,9 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 512 - 1; - data->bl = backlight_device_register("tosa-bl", &client->dev, data, - &bl_ops, &props); + data->bl = devm_backlight_device_register(&client->dev, "tosa-bl", + &client->dev, data, &bl_ops, + &props); if (IS_ERR(data->bl)) { ret = PTR_ERR(data->bl); goto err_reg; @@ -123,60 +122,51 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, err_reg: data->bl = NULL; -err_gpio_dir: - gpio_free(TOSA_GPIO_BL_C20MA); return ret; } -static int __devexit tosa_bl_remove(struct i2c_client *client) +static int tosa_bl_remove(struct i2c_client *client) { struct tosa_bl_data *data = i2c_get_clientdata(client); - backlight_device_unregister(data->bl); data->bl = NULL; - - gpio_free(TOSA_GPIO_BL_C20MA); - return 0; } -#ifdef CONFIG_PM -static int tosa_bl_suspend(struct i2c_client *client, pm_message_t pm) +#ifdef CONFIG_PM_SLEEP +static int tosa_bl_suspend(struct device *dev) { - struct tosa_bl_data *data = i2c_get_clientdata(client); + struct tosa_bl_data *data = dev_get_drvdata(dev); tosa_bl_set_backlight(data, 0); return 0; } -static int tosa_bl_resume(struct i2c_client *client) +static int tosa_bl_resume(struct device *dev) { - struct tosa_bl_data *data = i2c_get_clientdata(client); + struct tosa_bl_data *data = dev_get_drvdata(dev); backlight_update_status(data->bl); return 0; } -#else -#define tosa_bl_suspend NULL -#define tosa_bl_resume NULL #endif +static SIMPLE_DEV_PM_OPS(tosa_bl_pm_ops, tosa_bl_suspend, tosa_bl_resume); + static const struct i2c_device_id tosa_bl_id[] = { { "tosa-bl", 0 }, { }, }; - static struct i2c_driver tosa_bl_driver = { .driver = { .name = "tosa-bl", .owner = THIS_MODULE, + .pm = &tosa_bl_pm_ops, }, .probe = tosa_bl_probe, - .remove = __devexit_p(tosa_bl_remove), - .suspend = tosa_bl_suspend, - .resume = tosa_bl_resume, + .remove = tosa_bl_remove, .id_table = tosa_bl_id, }; diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 47823b8efff..f08d641ccd0 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -63,7 +63,7 @@ static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data) int tosa_bl_enable(struct spi_device *spi, int enable) { /* bl_enable GP04=1 otherwise GP04=0*/ - return tosa_tg_send(spi, TG_GPODR2, enable? 0x01 : 0x00); + return tosa_tg_send(spi, TG_GPODR2, enable ? 0x01 : 0x00); } EXPORT_SYMBOL(tosa_bl_enable); @@ -91,15 +91,17 @@ static void tosa_lcd_tg_on(struct tosa_lcd_data *data) tosa_tg_send(spi, TG_PNLCTL, value); /* TG LCD pannel power up */ - tosa_tg_send(spi, TG_PINICTL,0x4); + tosa_tg_send(spi, TG_PINICTL, 0x4); mdelay(50); /* TG LCD GVSS */ - tosa_tg_send(spi, TG_PINICTL,0x0); + tosa_tg_send(spi, TG_PINICTL, 0x0); if (!data->i2c) { - /* after the pannel is powered up the first time, we can access the i2c bus */ - /* so probe for the DAC */ + /* + * after the pannel is powered up the first time, + * we can access the i2c bus so probe for the DAC + */ struct i2c_adapter *adap = i2c_get_adapter(0); struct i2c_board_info info = { .type = "tosa-bl", @@ -115,11 +117,11 @@ static void tosa_lcd_tg_off(struct tosa_lcd_data *data) struct spi_device *spi = data->spi; /* TG LCD VHSA off */ - tosa_tg_send(spi, TG_PINICTL,0x4); + tosa_tg_send(spi, TG_PINICTL, 0x4); mdelay(50); /* TG LCD signal off */ - tosa_tg_send(spi, TG_PINICTL,0x6); + tosa_tg_send(spi, TG_PINICTL, 0x6); mdelay(50); /* TG Off */ @@ -169,7 +171,7 @@ static struct lcd_ops tosa_lcd_ops = { .set_mode = tosa_lcd_set_mode, }; -static int __devinit tosa_lcd_probe(struct spi_device *spi) +static int tosa_lcd_probe(struct spi_device *spi) { int ret; struct tosa_lcd_data *data; @@ -191,25 +193,21 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi) return ret; data->spi = spi; - dev_set_drvdata(&spi->dev, data); + spi_set_drvdata(spi, data); - ret = gpio_request(TOSA_GPIO_TG_ON, "tg #pwr"); + ret = devm_gpio_request_one(&spi->dev, TOSA_GPIO_TG_ON, + GPIOF_OUT_INIT_LOW, "tg #pwr"); if (ret < 0) - goto err_gpio_tg; + return ret; mdelay(60); - ret = gpio_direction_output(TOSA_GPIO_TG_ON, 0); - if (ret < 0) - goto err_gpio_dir; - - mdelay(60); tosa_lcd_tg_init(data); tosa_lcd_tg_on(data); - data->lcd = lcd_device_register("tosa-lcd", &spi->dev, data, - &tosa_lcd_ops); + data->lcd = devm_lcd_device_register(&spi->dev, "tosa-lcd", &spi->dev, + data, &tosa_lcd_ops); if (IS_ERR(data->lcd)) { ret = PTR_ERR(data->lcd); @@ -221,43 +219,34 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi) err_register: tosa_lcd_tg_off(data); -err_gpio_dir: - gpio_free(TOSA_GPIO_TG_ON); -err_gpio_tg: - dev_set_drvdata(&spi->dev, NULL); return ret; } -static int __devexit tosa_lcd_remove(struct spi_device *spi) +static int tosa_lcd_remove(struct spi_device *spi) { - struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); - - lcd_device_unregister(data->lcd); + struct tosa_lcd_data *data = spi_get_drvdata(spi); if (data->i2c) i2c_unregister_device(data->i2c); tosa_lcd_tg_off(data); - gpio_free(TOSA_GPIO_TG_ON); - dev_set_drvdata(&spi->dev, NULL); - return 0; } -#ifdef CONFIG_PM -static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int tosa_lcd_suspend(struct device *dev) { - struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); + struct tosa_lcd_data *data = dev_get_drvdata(dev); tosa_lcd_tg_off(data); return 0; } -static int tosa_lcd_resume(struct spi_device *spi) +static int tosa_lcd_resume(struct device *dev) { - struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); + struct tosa_lcd_data *data = dev_get_drvdata(dev); tosa_lcd_tg_init(data); if (POWER_IS_ON(data->lcd_power)) @@ -267,20 +256,18 @@ static int tosa_lcd_resume(struct spi_device *spi) return 0; } -#else -#define tosa_lcd_suspend NULL -#define tosa_lcd_resume NULL #endif +static SIMPLE_DEV_PM_OPS(tosa_lcd_pm_ops, tosa_lcd_suspend, tosa_lcd_resume); + static struct spi_driver tosa_lcd_driver = { .driver = { .name = "tosa-lcd", .owner = THIS_MODULE, + .pm = &tosa_lcd_pm_ops, }, .probe = tosa_lcd_probe, - .remove = __devexit_p(tosa_lcd_remove), - .suspend = tosa_lcd_suspend, - .resume = tosa_lcd_resume, + .remove = tosa_lcd_remove, }; module_spi_driver(tosa_lcd_driver); diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c new file mode 100644 index 00000000000..595dcf56102 --- /dev/null +++ b/drivers/video/backlight/tps65217_bl.c @@ -0,0 +1,341 @@ +/* + * tps65217_bl.c + * + * TPS65217 backlight driver + * + * Copyright (C) 2012 Matthias Kaehlcke + * Author: Matthias Kaehlcke <matthias@kaehlcke.net> + * + * 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 <linux/kernel.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/mfd/tps65217.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +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) { + 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; + } + } + + if (!of_property_read_u32(node, "default-brightness", &val)) { + if (val < 0 || + val > 100) { + dev_err(&pdev->dev, + "invalid 'default-brightness' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + + pdata->dft_brightness = val; + } + + 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 { + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + } + + tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), + GFP_KERNEL); + if (tps65217_bl == NULL) + 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 = devm_backlight_device_register(&pdev->dev, 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 = pdata->dft_brightness; + backlight_update_status(tps65217_bl->bl); + platform_set_drvdata(pdev, tps65217_bl); + + return 0; +} + +static struct platform_driver tps65217_bl_driver = { + .probe = tps65217_bl_probe, + .driver = { + .owner = THIS_MODULE, + .name = "tps65217-bl", + }, +}; + +module_platform_driver(tps65217_bl_driver); + +MODULE_DESCRIPTION("TPS65217 Backlight driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Matthias Kaehlcke <matthias@kaehlcke.net>"); diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c index b617fae9aa2..d538947a67d 100644 --- a/drivers/video/backlight/vgg2432a4.c +++ b/drivers/video/backlight/vgg2432a4.c @@ -26,7 +26,7 @@ /* Device initialisation sequences */ -static struct ili9320_reg vgg_init1[] = { +static const struct ili9320_reg vgg_init1[] = { { .address = ILI9320_POWER1, .value = ILI9320_POWER1_AP(0) | ILI9320_POWER1_BT(0), @@ -43,7 +43,7 @@ static struct ili9320_reg vgg_init1[] = { }, }; -static struct ili9320_reg vgg_init2[] = { +static const struct ili9320_reg vgg_init2[] = { { .address = ILI9320_POWER1, .value = (ILI9320_POWER1_AP(3) | ILI9320_POWER1_APE | @@ -54,7 +54,7 @@ static struct ili9320_reg vgg_init2[] = { } }; -static struct ili9320_reg vgg_gamma[] = { +static const struct ili9320_reg vgg_gamma[] = { { .address = ILI9320_GAMMA1, .value = 0x0000, @@ -89,7 +89,7 @@ static struct ili9320_reg vgg_gamma[] = { }; -static struct ili9320_reg vgg_init0[] = { +static const struct ili9320_reg vgg_init0[] = { [0] = { /* set direction and scan mode gate */ .address = ILI9320_DRIVER, @@ -205,19 +205,15 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd, return ret; } -#ifdef CONFIG_PM -static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int vgg2432a4_suspend(struct device *dev) { - return ili9320_suspend(dev_get_drvdata(&spi->dev), state); + return ili9320_suspend(dev_get_drvdata(dev)); } - -static int vgg2432a4_resume(struct spi_device *spi) +static int vgg2432a4_resume(struct device *dev) { - return ili9320_resume(dev_get_drvdata(&spi->dev)); + return ili9320_resume(dev_get_drvdata(dev)); } -#else -#define vgg2432a4_suspend NULL -#define vgg2432a4_resume NULL #endif static struct ili9320_client vgg2432a4_client = { @@ -227,7 +223,7 @@ static struct ili9320_client vgg2432a4_client = { /* Device probe */ -static int __devinit vgg2432a4_probe(struct spi_device *spi) +static int vgg2432a4_probe(struct spi_device *spi) { int ret; @@ -240,26 +236,27 @@ static int __devinit vgg2432a4_probe(struct spi_device *spi) return 0; } -static int __devexit vgg2432a4_remove(struct spi_device *spi) +static int vgg2432a4_remove(struct spi_device *spi) { - return ili9320_remove(dev_get_drvdata(&spi->dev)); + return ili9320_remove(spi_get_drvdata(spi)); } static void vgg2432a4_shutdown(struct spi_device *spi) { - ili9320_shutdown(dev_get_drvdata(&spi->dev)); + ili9320_shutdown(spi_get_drvdata(spi)); } +static SIMPLE_DEV_PM_OPS(vgg2432a4_pm_ops, vgg2432a4_suspend, vgg2432a4_resume); + static struct spi_driver vgg2432a4_driver = { .driver = { .name = "VGG2432A4", .owner = THIS_MODULE, + .pm = &vgg2432a4_pm_ops, }, .probe = vgg2432a4_probe, - .remove = __devexit_p(vgg2432a4_remove), + .remove = vgg2432a4_remove, .shutdown = vgg2432a4_shutdown, - .suspend = vgg2432a4_suspend, - .resume = vgg2432a4_resume, }; module_spi_driver(vgg2432a4_driver); diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 9e5517a3a52..8b9455e9306 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -123,7 +123,7 @@ static const struct backlight_ops wm831x_backlight_ops = { static int wm831x_backlight_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); - struct wm831x_pdata *wm831x_pdata; + struct wm831x_pdata *wm831x_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_backlight_pdata *pdata; struct wm831x_backlight_data *data; struct backlight_device *bl; @@ -131,12 +131,10 @@ static int wm831x_backlight_probe(struct platform_device *pdev) int ret, i, max_isel, isink_reg, dcdc_cfg; /* We need platform data */ - if (pdev->dev.parent->platform_data) { - wm831x_pdata = pdev->dev.parent->platform_data; + if (wm831x_pdata) pdata = wm831x_pdata->backlight; - } else { + else pdata = NULL; - } if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); @@ -197,8 +195,8 @@ static int wm831x_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = max_isel; - bl = backlight_device_register("wm831x", &pdev->dev, data, - &wm831x_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, "wm831x", &pdev->dev, + data, &wm831x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -216,21 +214,12 @@ static int wm831x_backlight_probe(struct platform_device *pdev) return 0; } -static int wm831x_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; -} - static struct platform_driver wm831x_backlight_driver = { .driver = { .name = "wm831x-backlight", .owner = THIS_MODULE, }, .probe = wm831x_backlight_probe, - .remove = wm831x_backlight_remove, }; module_platform_driver(wm831x_backlight_driver); |
