From 81ce6864444facc95ba7fe25575153425106c985 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Mar 2012 15:01:59 -0700 Subject: backlight: convert backlight i2c drivers to module_i2c_driver Factor out some boilerplate code for i2c driver registration into module_i2c_driver. Signed-off-by: Axel Lin Cc: Michael Hennerich Cc: Dmitry Baryshkov Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/adp8860_bl.c | 12 +----------- drivers/video/backlight/adp8870_bl.c | 12 +----------- drivers/video/backlight/tosa_bl.c | 13 +------------ 3 files changed, 3 insertions(+), 34 deletions(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 378276c9d3cf..550dbf0bb896 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -819,17 +819,7 @@ static struct i2c_driver adp8860_driver = { .id_table = adp8860_id, }; -static int __init adp8860_init(void) -{ - return i2c_add_driver(&adp8860_driver); -} -module_init(adp8860_init); - -static void __exit adp8860_exit(void) -{ - i2c_del_driver(&adp8860_driver); -} -module_exit(adp8860_exit); +module_i2c_driver(adp8860_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Michael Hennerich "); diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 6735059376d6..9be58c6f18f1 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -991,17 +991,7 @@ static struct i2c_driver adp8870_driver = { .id_table = adp8870_id, }; -static int __init adp8870_init(void) -{ - return i2c_add_driver(&adp8870_driver); -} -module_init(adp8870_init); - -static void __exit adp8870_exit(void) -{ - i2c_del_driver(&adp8870_driver); -} -module_exit(adp8870_exit); +module_i2c_driver(adp8870_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Michael Hennerich "); diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 425a7365470b..2b241abced43 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -181,18 +181,7 @@ static struct i2c_driver tosa_bl_driver = { .id_table = tosa_bl_id, }; -static int __init tosa_bl_init(void) -{ - return i2c_add_driver(&tosa_bl_driver); -} - -static void __exit tosa_bl_exit(void) -{ - i2c_del_driver(&tosa_bl_driver); -} - -module_init(tosa_bl_init); -module_exit(tosa_bl_exit); +module_i2c_driver(tosa_bl_driver); MODULE_AUTHOR("Dmitry Baryshkov"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 462dd83833065a6b3add3f102f4fe69efa1422e9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Mar 2012 15:01:59 -0700 Subject: backlight: convert backlight spi drivers to module_spi_driver Factor out some boilerplate code for spi driver registration into module_spi_driver. Signed-off-by: Axel Lin Acked-by: Jingoo Han Cc: Eric Miao Acked-by: Alberto Panizzo Cc: Donghwa Lee Acked-by: Marek Vasut Cc: Haavard Skinnemoen Cc: InKi Dae Cc: Dmitry Baryshkov Cc: Ben Dooks Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/ams369fg06.c | 13 +------------ drivers/video/backlight/corgi_lcd.c | 12 +----------- drivers/video/backlight/l4f00242t03.c | 13 +------------ drivers/video/backlight/ld9040.c | 13 +------------ drivers/video/backlight/lms283gf05.c | 13 +------------ drivers/video/backlight/ltv350qv.c | 12 +----------- drivers/video/backlight/s6e63m0.c | 13 +------------ drivers/video/backlight/tdo24m.c | 12 +----------- drivers/video/backlight/tosa_lcd.c | 13 +------------ drivers/video/backlight/vgg2432a4.c | 15 +-------------- 10 files changed, 10 insertions(+), 119 deletions(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 7838a23fbdd1..7bdadc790117 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -629,18 +629,7 @@ static struct spi_driver ams369fg06_driver = { .resume = ams369fg06_resume, }; -static int __init ams369fg06_init(void) -{ - return spi_register_driver(&ams369fg06_driver); -} - -static void __exit ams369fg06_exit(void) -{ - spi_unregister_driver(&ams369fg06_driver); -} - -module_init(ams369fg06_init); -module_exit(ams369fg06_exit); +module_spi_driver(ams369fg06_driver); MODULE_AUTHOR("Jingoo Han "); MODULE_DESCRIPTION("ams369fg06 LCD Driver"); diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index c6533bad26f8..6dab13fe562e 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -629,17 +629,7 @@ static struct spi_driver corgi_lcd_driver = { .resume = corgi_lcd_resume, }; -static int __init corgi_lcd_init(void) -{ - return spi_register_driver(&corgi_lcd_driver); -} -module_init(corgi_lcd_init); - -static void __exit corgi_lcd_exit(void) -{ - spi_unregister_driver(&corgi_lcd_driver); -} -module_exit(corgi_lcd_exit); +module_spi_driver(corgi_lcd_driver); MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00"); MODULE_AUTHOR("Eric Miao "); diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 27d1d7a29c77..6022b67285ec 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -274,18 +274,7 @@ static struct spi_driver l4f00242t03_driver = { .shutdown = l4f00242t03_shutdown, }; -static __init int l4f00242t03_init(void) -{ - return spi_register_driver(&l4f00242t03_driver); -} - -static __exit void l4f00242t03_exit(void) -{ - spi_unregister_driver(&l4f00242t03_driver); -} - -module_init(l4f00242t03_init); -module_exit(l4f00242t03_exit); +module_spi_driver(l4f00242t03_driver); MODULE_AUTHOR("Alberto Panizzo "); MODULE_DESCRIPTION("EPSON L4F00242T03 LCD"); diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 78dafc0c8fc5..efd352be21ae 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -856,18 +856,7 @@ static struct spi_driver ld9040_driver = { .resume = ld9040_resume, }; -static int __init ld9040_init(void) -{ - return spi_register_driver(&ld9040_driver); -} - -static void __exit ld9040_exit(void) -{ - spi_unregister_driver(&ld9040_driver); -} - -module_init(ld9040_init); -module_exit(ld9040_exit); +module_spi_driver(ld9040_driver); MODULE_AUTHOR("Donghwa Lee "); MODULE_DESCRIPTION("ld9040 LCD Driver"); diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index 4ec78cfe26ea..4161f9e3982a 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -226,18 +226,7 @@ static struct spi_driver lms283gf05_driver = { .remove = __devexit_p(lms283gf05_remove), }; -static __init int lms283gf05_init(void) -{ - return spi_register_driver(&lms283gf05_driver); -} - -static __exit void lms283gf05_exit(void) -{ - spi_unregister_driver(&lms283gf05_driver); -} - -module_init(lms283gf05_init); -module_exit(lms283gf05_exit); +module_spi_driver(lms283gf05_driver); MODULE_AUTHOR("Marek Vasut "); MODULE_DESCRIPTION("LCD283GF05 LCD"); diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index cca43c06d3c8..333949ff3265 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -321,17 +321,7 @@ static struct spi_driver ltv350qv_driver = { .resume = ltv350qv_resume, }; -static int __init ltv350qv_init(void) -{ - return spi_register_driver(<v350qv_driver); -} - -static void __exit ltv350qv_exit(void) -{ - spi_unregister_driver(<v350qv_driver); -} -module_init(ltv350qv_init); -module_exit(ltv350qv_exit); +module_spi_driver(ltv350qv_driver); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver"); diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 516db703dd24..e264f55b2574 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -909,18 +909,7 @@ static struct spi_driver s6e63m0_driver = { .resume = s6e63m0_resume, }; -static int __init s6e63m0_init(void) -{ - return spi_register_driver(&s6e63m0_driver); -} - -static void __exit s6e63m0_exit(void) -{ - spi_unregister_driver(&s6e63m0_driver); -} - -module_init(s6e63m0_init); -module_exit(s6e63m0_exit); +module_spi_driver(s6e63m0_driver); MODULE_AUTHOR("InKi Dae "); MODULE_DESCRIPTION("S6E63M0 LCD Driver"); diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 1997e12a1057..2368b8e5f89e 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -459,17 +459,7 @@ static struct spi_driver tdo24m_driver = { .resume = tdo24m_resume, }; -static int __init tdo24m_init(void) -{ - return spi_register_driver(&tdo24m_driver); -} -module_init(tdo24m_init); - -static void __exit tdo24m_exit(void) -{ - spi_unregister_driver(&tdo24m_driver); -} -module_exit(tdo24m_exit); +module_spi_driver(tdo24m_driver); MODULE_AUTHOR("Eric Miao "); MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel"); diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 772f6015219a..a2161f631a83 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -285,18 +285,7 @@ static struct spi_driver tosa_lcd_driver = { .resume = tosa_lcd_resume, }; -static int __init tosa_lcd_init(void) -{ - return spi_register_driver(&tosa_lcd_driver); -} - -static void __exit tosa_lcd_exit(void) -{ - spi_unregister_driver(&tosa_lcd_driver); -} - -module_init(tosa_lcd_init); -module_exit(tosa_lcd_exit); +module_spi_driver(tosa_lcd_driver); MODULE_AUTHOR("Dmitry Baryshkov"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c index b49063c831e7..b617fae9aa26 100644 --- a/drivers/video/backlight/vgg2432a4.c +++ b/drivers/video/backlight/vgg2432a4.c @@ -262,20 +262,7 @@ static struct spi_driver vgg2432a4_driver = { .resume = vgg2432a4_resume, }; -/* Device driver initialisation */ - -static int __init vgg2432a4_init(void) -{ - return spi_register_driver(&vgg2432a4_driver); -} - -static void __exit vgg2432a4_exit(void) -{ - spi_unregister_driver(&vgg2432a4_driver); -} - -module_init(vgg2432a4_init); -module_exit(vgg2432a4_exit); +module_spi_driver(vgg2432a4_driver); MODULE_AUTHOR("Ben Dooks "); MODULE_DESCRIPTION("VGG2432A4 LCD Driver"); -- cgit v1.2.3 From 1107d40a50956146d1272f5cffcdf1d83f7e703e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 23 Mar 2012 15:02:00 -0700 Subject: drivers/video/backlight/wm831x_bl.c: use devm_ functions The various devm_ functions allocate memory that is released when a driver detaches. This patch uses these functions for data that is allocated in the probe function of a platform device and is only freed in the remove function. Signed-off-by: Julia Lawall Cc: Dimitris Papastamos Cc: Richard Purdie Cc: Florian Tobias Schandinat Acked-by: Mark Brown Cc: Michael Hennerich Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/wm831x_bl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 4e915f5eca99..5d365deb5f82 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -186,7 +186,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev) if (ret < 0) return ret; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -200,7 +200,6 @@ static int wm831x_backlight_probe(struct platform_device *pdev) &wm831x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - kfree(data); return PTR_ERR(bl); } @@ -211,7 +210,6 @@ static int wm831x_backlight_probe(struct platform_device *pdev) /* Disable the DCDC if it was started so we can bootstrap */ wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0); - backlight_update_status(bl); return 0; @@ -220,10 +218,8 @@ static int wm831x_backlight_probe(struct platform_device *pdev) static int wm831x_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); - struct wm831x_backlight_data *data = bl_get_data(bl); backlight_device_unregister(bl); - kfree(data); return 0; } -- cgit v1.2.3 From ce969228fdb54a7e3d7cc1ed27367fd4b9525d74 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 23 Mar 2012 15:02:00 -0700 Subject: drivers/video/backlight: use devm_ functions The various devm_ functions allocate memory that is released when a driver detaches. This patch uses these functions for data that is allocated in the probe function of a platform device and is only freed in the remove function. Signed-off-by: Julia Lawall Cc: Dimitris Papastamos Cc: Richard Purdie Cc: Florian Tobias Schandinat Cc: Mark Brown Cc: Michael Hennerich Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/88pm860x_bl.c | 8 ++------ drivers/video/backlight/aat2870_bl.c | 9 ++++----- drivers/video/backlight/cr_bllcd.c | 3 +-- drivers/video/backlight/da903x_bl.c | 6 +----- drivers/video/backlight/max8925_bl.c | 7 ++----- drivers/video/backlight/omap1_bl.c | 9 +++------ drivers/video/backlight/pcf50633-backlight.c | 16 +++------------- drivers/video/backlight/pwm_bl.c | 7 ++----- 8 files changed, 18 insertions(+), 47 deletions(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index a1376dc73d71..915943af3f21 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -187,7 +187,8 @@ static int pm860x_backlight_probe(struct platform_device *pdev) return -EINVAL; } - data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data), + GFP_KERNEL); if (data == NULL) return -ENOMEM; strncpy(name, res->name, MFD_NAME_SIZE); @@ -200,7 +201,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev) data->port = pdata->flags; if (data->port < 0) { dev_err(&pdev->dev, "wrong platform data is assigned"); - kfree(data); return -EINVAL; } @@ -211,7 +211,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev) &pm860x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - kfree(data); return PTR_ERR(bl); } bl->props.brightness = MAX_BRIGHTNESS; @@ -247,17 +246,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev) return 0; out: backlight_device_unregister(bl); - kfree(data); return ret; } static int pm860x_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); - struct pm860x_backlight_data *data = bl_get_data(bl); backlight_device_unregister(bl); - kfree(data); return 0; } diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 331f1ef1dad5..7ff752288b92 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -145,7 +145,9 @@ static int aat2870_bl_probe(struct platform_device *pdev) goto out; } - aat2870_bl = kzalloc(sizeof(struct aat2870_bl_driver_data), GFP_KERNEL); + aat2870_bl = devm_kzalloc(&pdev->dev, + sizeof(struct aat2870_bl_driver_data), + GFP_KERNEL); if (!aat2870_bl) { dev_err(&pdev->dev, "Failed to allocate memory for aat2870 backlight\n"); @@ -162,7 +164,7 @@ static int aat2870_bl_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed allocate memory for backlight device\n"); ret = PTR_ERR(bd); - goto out_kfree; + goto out; } aat2870_bl->pdev = pdev; @@ -199,8 +201,6 @@ static int aat2870_bl_probe(struct platform_device *pdev) out_bl_dev_unregister: backlight_device_unregister(bd); -out_kfree: - kfree(aat2870_bl); out: return ret; } @@ -215,7 +215,6 @@ static int aat2870_bl_remove(struct platform_device *pdev) backlight_update_status(bd); backlight_device_unregister(bd); - kfree(aat2870_bl); return 0; } diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 6c8c54041fae..22489eb5f3e0 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -212,7 +212,7 @@ static int cr_backlight_probe(struct platform_device *pdev) &gpio_bar); gpio_bar &= ~0x3F; - crp = kzalloc(sizeof(*crp), GFP_KERNEL); + crp = devm_kzalloc(&pdev->dev, sizeof(*crp), GFP_KERNEL); if (!crp) { lcd_device_unregister(ldp); backlight_device_unregister(bdp); @@ -243,7 +243,6 @@ static int cr_backlight_remove(struct platform_device *pdev) backlight_device_unregister(crp->cr_backlight_device); lcd_device_unregister(crp->cr_lcd_device); pci_dev_put(lpc_dev); - kfree(crp); return 0; } diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index abb4a06268f1..30e19681a30b 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -110,7 +110,7 @@ static int da903x_backlight_probe(struct platform_device *pdev) struct backlight_properties props; int max_brightness; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -124,7 +124,6 @@ static int da903x_backlight_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "invalid backlight device ID(%d)\n", pdev->id); - kfree(data); return -EINVAL; } @@ -143,7 +142,6 @@ static int da903x_backlight_probe(struct platform_device *pdev) &da903x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - kfree(data); return PTR_ERR(bl); } @@ -157,10 +155,8 @@ static int da903x_backlight_probe(struct platform_device *pdev) static int da903x_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); - struct da903x_backlight_data *data = bl_get_data(bl); backlight_device_unregister(bl); - kfree(data); return 0; } diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index c915e3b53886..e833ac72e063 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -129,7 +129,8 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) return -EINVAL; } - data = kzalloc(sizeof(struct max8925_backlight_data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data), + GFP_KERNEL); if (data == NULL) return -ENOMEM; strncpy(name, res->name, MAX8925_NAME_SIZE); @@ -143,7 +144,6 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - kfree(data); return PTR_ERR(bl); } bl->props.brightness = MAX_BRIGHTNESS; @@ -165,17 +165,14 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) return 0; out: backlight_device_unregister(bl); - kfree(data); return ret; } static int __devexit max8925_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); - struct max8925_backlight_data *data = bl_get_data(bl); backlight_device_unregister(bl); - kfree(data); return 0; } diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index d8cde277ec83..0175bfb08a1c 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -141,7 +141,8 @@ static int omapbl_probe(struct platform_device *pdev) if (!pdata) return -ENXIO; - bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL); + bl = devm_kzalloc(&pdev->dev, sizeof(struct omap_backlight), + GFP_KERNEL); if (unlikely(!bl)) return -ENOMEM; @@ -150,10 +151,8 @@ static int omapbl_probe(struct platform_device *pdev) props.max_brightness = OMAPBL_MAX_INTENSITY; dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops, &props); - if (IS_ERR(dev)) { - kfree(bl); + if (IS_ERR(dev)) return PTR_ERR(dev); - } bl->powermode = FB_BLANK_POWERDOWN; bl->current_intensity = 0; @@ -177,10 +176,8 @@ static int omapbl_probe(struct platform_device *pdev) static int omapbl_remove(struct platform_device *pdev) { struct backlight_device *dev = platform_get_drvdata(pdev); - struct omap_backlight *bl = dev_get_drvdata(&dev->dev); backlight_device_unregister(dev); - kfree(bl); return 0; } diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index 13e88b71daec..c65853cb9740 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -101,14 +101,13 @@ static const struct backlight_ops pcf50633_bl_ops = { static int __devinit pcf50633_bl_probe(struct platform_device *pdev) { - int ret; struct pcf50633_bl *pcf_bl; struct device *parent = pdev->dev.parent; struct pcf50633_platform_data *pcf50633_data = parent->platform_data; struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; struct backlight_properties bl_props; - pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL); + pcf_bl = devm_kzalloc(&pdev->dev, sizeof(*pcf_bl), GFP_KERNEL); if (!pcf_bl) return -ENOMEM; @@ -129,10 +128,8 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, &pcf50633_bl_ops, &bl_props); - if (IS_ERR(pcf_bl->bl)) { - ret = PTR_ERR(pcf_bl->bl); - goto err_free; - } + if (IS_ERR(pcf_bl->bl)) + return PTR_ERR(pcf_bl->bl); platform_set_drvdata(pdev, pcf_bl); @@ -145,11 +142,6 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) backlight_update_status(pcf_bl->bl); return 0; - -err_free: - kfree(pcf_bl); - - return ret; } static int __devexit pcf50633_bl_remove(struct platform_device *pdev) @@ -160,8 +152,6 @@ static int __devexit pcf50633_bl_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - kfree(pcf_bl); - return 0; } diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 7496d04e1d3c..342b7d7cbb63 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -102,7 +102,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) return ret; } - pb = kzalloc(sizeof(*pb), GFP_KERNEL); + pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL); if (!pb) { dev_err(&pdev->dev, "no memory for state\n"); ret = -ENOMEM; @@ -121,7 +121,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) if (IS_ERR(pb->pwm)) { dev_err(&pdev->dev, "unable to request PWM for backlight\n"); ret = PTR_ERR(pb->pwm); - goto err_pwm; + goto err_alloc; } else dev_dbg(&pdev->dev, "got pwm for backlight\n"); @@ -144,8 +144,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) err_bl: pwm_free(pb->pwm); -err_pwm: - kfree(pb); err_alloc: if (data->exit) data->exit(&pdev->dev); @@ -162,7 +160,6 @@ static int pwm_backlight_remove(struct platform_device *pdev) pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); pwm_free(pb->pwm); - kfree(pb); if (data->exit) data->exit(&pdev->dev); return 0; -- cgit v1.2.3 From 050ea48bbfc80b6aa81f8df0d9f25e6e47d96e98 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 23 Mar 2012 15:02:01 -0700 Subject: drivers/video/backlight/adp5520_bl.c: use devm_ functions The various devm_ functions allocate memory that is released when a driver detaches. This patch uses these functions for data that is allocated in the probe function of a platform device and is only freed in the remove function. Signed-off-by: Julia Lawall Cc: Dimitris Papastamos Cc: Richard Purdie Cc: Florian Tobias Schandinat Cc: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/adp5520_bl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index 2e630bf1164c..4911ea7989c8 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -289,7 +289,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) struct adp5520_bl *data; int ret = 0; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -298,7 +298,6 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) if (data->pdata == NULL) { dev_err(&pdev->dev, "missing platform data\n"); - kfree(data); return -ENODEV; } @@ -314,7 +313,6 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) &adp5520_bl_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - kfree(data); return PTR_ERR(bl); } @@ -326,7 +324,6 @@ 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); - kfree(data); } platform_set_drvdata(pdev, bl); @@ -348,7 +345,6 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev) &adp5520_bl_attr_group); backlight_device_unregister(bl); - kfree(data); return 0; } -- cgit v1.2.3 From 7be865ab8634d4ec2a6bdb9459b268cd60e832af Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Fri, 23 Mar 2012 15:02:01 -0700 Subject: backlight: new backlight driver for LP855x devices THis driver supports TI LP8550/LP8551/LP8552/LP8553/LP8556 backlight devices. The brightness can be controlled by the I2C or PWM input. The lp855x driver provides both modes. For the PWM control, pwm-specific functions can be defined in the platform data. And some information can be read via the sysfs(lp855x device attributes). For details, please refer to Documentation/backlight/lp855x-driver.txt. [axel.lin@gmail.com: add missing mutex_unlock in lp855x_read_byte() error path] [axel.lin@gmail.com: check platform data in lp855x_probe()] [axel.lin@gmail.com: small cleanups] [dan.carpenter@oracle.com: silence a compiler warning] [axel.lin@gmail.com: use id->driver_data to differentiate lp855x chips] [akpm@linux-foundation.org: simplify boolean return expression] Signed-off-by: Milo(Woogyom) Kim Signed-off-by: Axel Lin Signed-off-by: Dan Carpenter Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/backlight/lp855x-driver.txt | 78 +++++++ drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/lp855x_bl.c | 331 ++++++++++++++++++++++++++++++ include/linux/lp855x.h | 131 ++++++++++++ 5 files changed, 548 insertions(+) create mode 100644 Documentation/backlight/lp855x-driver.txt create mode 100644 drivers/video/backlight/lp855x_bl.c create mode 100644 include/linux/lp855x.h (limited to 'drivers/video/backlight') diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt new file mode 100644 index 000000000000..f5e4caafab7d --- /dev/null +++ b/Documentation/backlight/lp855x-driver.txt @@ -0,0 +1,78 @@ +Kernel driver lp855x +==================== + +Backlight driver for LP855x ICs + +Supported chips: + Texas Instruments LP8550, LP8551, LP8552, LP8553 and LP8556 + +Author: Milo(Woogyom) Kim + +Description +----------- + +* Brightness control + +Brightness can be controlled by the pwm input or the i2c command. +The lp855x driver supports both cases. + +* Device attributes + +1) bl_ctl_mode +Backlight control mode. +Value : pwm based or register based + +2) chip_id +The lp855x chip id. +Value : lp8550/lp8551/lp8552/lp8553/lp8556 + +Platform data for lp855x +------------------------ + +For supporting platform specific data, the lp855x platform data can be used. + +* name : Backlight driver name. If it is not defined, default name is set. +* mode : Brightness control mode. PWM or register based. +* device_control : Value of DEVICE CONTROL register. +* initial_brightness : Initial value of backlight brightness. +* pwm_data : Platform specific pwm generation functions. + Only valid when brightness is pwm input mode. + Functions should be implemented by PWM driver. + - pwm_set_intensity() : set duty of PWM + - pwm_get_intensity() : get current duty of PWM +* load_new_rom_data : + 0 : use default configuration data + 1 : update values of eeprom or eprom registers on loading driver +* size_program : Total size of lp855x_rom_data. +* rom_data : List of new eeprom/eprom registers. + +example 1) lp8552 platform data : i2c register mode with new eeprom data + +#define EEPROM_A5_ADDR 0xA5 +#define EEPROM_A5_VAL 0x4f /* EN_VSYNC=0 */ + +static struct lp855x_rom_data lp8552_eeprom_arr[] = { + {EEPROM_A5_ADDR, EEPROM_A5_VAL}, +}; + +static struct lp855x_platform_data lp8552_pdata = { + .name = "lcd-bl", + .mode = REGISTER_BASED, + .device_control = I2C_CONFIG(LP8552), + .initial_brightness = INITIAL_BRT, + .load_new_rom_data = 1, + .size_program = ARRAY_SIZE(lp8552_eeprom_arr), + .rom_data = lp8552_eeprom_arr, +}; + +example 2) lp8556 platform data : pwm input mode with default rom data + +static struct lp855x_platform_data lp8556_pdata = { + .mode = PWM_BASED, + .device_control = PWM_CONFIG(LP8556), + .initial_brightness = INITIAL_BRT, + .pwm_data = { + .pwm_set_intensity = platform_pwm_set_intensity, + .pwm_get_intensity = platform_pwm_get_intensity, + }, +}; diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 681b36929fe4..49e7d83f869f 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -334,6 +334,13 @@ config BACKLIGHT_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the backlight driver. +config BACKLIGHT_LP855X + tristate "Backlight driver for TI LP855X" + depends on BACKLIGHT_CLASS_DEVICE && I2C + help + This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556 + backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index af5cf654ec7c..0ee06e0832bd 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_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_PROGEAR) += progear_bl.o obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c new file mode 100644 index 000000000000..72a0e0c917cf --- /dev/null +++ b/drivers/video/backlight/lp855x_bl.c @@ -0,0 +1,331 @@ +/* + * TI LP855x Backlight Driver + * + * Copyright (C) 2011 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 +#include +#include +#include +#include +#include + +/* Registers */ +#define BRIGHTNESS_CTRL (0x00) +#define DEVICE_CTRL (0x01) + +#define BUF_SIZE 20 +#define DEFAULT_BL_NAME "lcd-backlight" +#define MAX_BRIGHTNESS 255 + +struct lp855x { + const char *chipname; + enum lp855x_chip_id chip_id; + struct i2c_client *client; + struct backlight_device *bl; + struct device *dev; + struct mutex xfer_lock; + struct lp855x_platform_data *pdata; +}; + +static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data) +{ + int ret; + + 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; +} + +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; +} + +static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) +{ + u8 start, end; + + switch (lp->chip_id) { + case LP8550: + case LP8551: + case LP8552: + case LP8553: + start = EEPROM_START; + end = EEPROM_END; + break; + case LP8556: + start = EPROM_START; + end = EPROM_END; + break; + default: + return false; + } + + return (addr >= start && addr <= end); +} + +static int lp855x_init_registers(struct lp855x *lp) +{ + u8 val, addr; + int i, ret; + struct lp855x_platform_data *pd = lp->pdata; + + val = pd->initial_brightness; + ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val); + if (ret) + return ret; + + val = pd->device_control; + ret = lp855x_write_byte(lp, DEVICE_CTRL, val); + if (ret) + return ret; + + if (pd->load_new_rom_data && pd->size_program) { + for (i = 0; i < pd->size_program; i++) { + addr = pd->rom_data[i].addr; + val = pd->rom_data[i].val; + if (!lp855x_is_valid_rom_area(lp, addr)) + continue; + + ret = lp855x_write_byte(lp, addr, val); + if (ret) + return ret; + } + } + + return ret; +} + +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) + bl->props.brightness = 0; + + if (mode == PWM_BASED) { + struct lp855x_pwm_data *pd = &lp->pdata->pwm_data; + int br = bl->props.brightness; + int max_br = bl->props.max_brightness; + + if (pd->pwm_set_intensity) + pd->pwm_set_intensity(br, max_br); + + } else if (mode == REGISTER_BASED) { + u8 val = bl->props.brightness; + lp855x_write_byte(lp, BRIGHTNESS_CTRL, val); + } + + return 0; +} + +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; +} + +static const struct backlight_ops lp855x_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lp855x_bl_update_status, + .get_brightness = lp855x_bl_get_brightness, +}; + +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; + + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = MAX_BRIGHTNESS; + + if (pdata->initial_brightness > props.max_brightness) + pdata->initial_brightness = props.max_brightness; + + props.brightness = pdata->initial_brightness; + + bl = backlight_device_register(name, lp->dev, lp, + &lp855x_bl_ops, &props); + if (IS_ERR(bl)) + return PTR_ERR(bl); + + lp->bl = bl; + + 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); +} + +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) + strmode = "pwm based"; + else if (mode == REGISTER_BASED) + strmode = "register based"; + + return scnprintf(buf, BUF_SIZE, "%s\n", strmode); +} + +static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL); +static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL); + +static struct attribute *lp855x_attributes[] = { + &dev_attr_chip_id.attr, + &dev_attr_bl_ctl_mode.attr, + NULL, +}; + +static const struct attribute_group lp855x_attr_group = { + .attrs = lp855x_attributes, +}; + +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; + int ret; + + if (!pdata) { + dev_err(&cl->dev, "no platform data supplied\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -EIO; + + lp = devm_kzalloc(&cl->dev, sizeof(struct lp855x), GFP_KERNEL); + if (!lp) + return -ENOMEM; + + mode = pdata->mode; + lp->client = cl; + lp->dev = &cl->dev; + lp->pdata = pdata; + lp->chipname = id->name; + lp->chip_id = id->driver_data; + i2c_set_clientdata(cl, lp); + + mutex_init(&lp->xfer_lock); + + ret = lp855x_init_registers(lp); + if (ret) { + dev_err(lp->dev, "i2c communication err: %d", ret); + if (mode == REGISTER_BASED) + goto err_dev; + } + + ret = lp855x_backlight_register(lp); + if (ret) { + dev_err(lp->dev, + "failed to register backlight. err: %d\n", ret); + goto err_dev; + } + + 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; + } + + 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) +{ + 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 i2c_device_id lp855x_ids[] = { + {"lp8550", LP8550}, + {"lp8551", LP8551}, + {"lp8552", LP8552}, + {"lp8553", LP8553}, + {"lp8556", LP8556}, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp855x_ids); + +static struct i2c_driver lp855x_driver = { + .driver = { + .name = "lp855x", + }, + .probe = lp855x_probe, + .remove = __devexit_p(lp855x_remove), + .id_table = lp855x_ids, +}; + +module_i2c_driver(lp855x_driver); + +MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver"); +MODULE_AUTHOR("Milo Kim "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/lp855x.h b/include/linux/lp855x.h new file mode 100644 index 000000000000..781a490a451b --- /dev/null +++ b/include/linux/lp855x.h @@ -0,0 +1,131 @@ +/* + * LP855x Backlight Driver + * + * Copyright (C) 2011 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. + * + */ + +#ifndef _LP855X_H +#define _LP855X_H + +#define BL_CTL_SHFT (0) +#define BRT_MODE_SHFT (1) +#define BRT_MODE_MASK (0x06) + +/* Enable backlight. Only valid when BRT_MODE=10(I2C only) */ +#define ENABLE_BL (1) +#define DISABLE_BL (0) + +#define I2C_CONFIG(id) id ## _I2C_CONFIG +#define PWM_CONFIG(id) id ## _PWM_CONFIG + +/* DEVICE CONTROL register - LP8550 */ +#define LP8550_PWM_CONFIG (LP8550_PWM_ONLY << BRT_MODE_SHFT) +#define LP8550_I2C_CONFIG ((ENABLE_BL << BL_CTL_SHFT) | \ + (LP8550_I2C_ONLY << BRT_MODE_SHFT)) + +/* DEVICE CONTROL register - LP8551 */ +#define LP8551_PWM_CONFIG LP8550_PWM_CONFIG +#define LP8551_I2C_CONFIG LP8550_I2C_CONFIG + +/* DEVICE CONTROL register - LP8552 */ +#define LP8552_PWM_CONFIG LP8550_PWM_CONFIG +#define LP8552_I2C_CONFIG LP8550_I2C_CONFIG + +/* DEVICE CONTROL register - LP8553 */ +#define LP8553_PWM_CONFIG LP8550_PWM_CONFIG +#define LP8553_I2C_CONFIG LP8550_I2C_CONFIG + +/* DEVICE CONTROL register - LP8556 */ +#define LP8556_PWM_CONFIG (LP8556_PWM_ONLY << BRT_MODE_SHFT) +#define LP8556_COMB1_CONFIG (LP8556_COMBINED1 << BRT_MODE_SHFT) +#define LP8556_I2C_CONFIG ((ENABLE_BL << BL_CTL_SHFT) | \ + (LP8556_I2C_ONLY << BRT_MODE_SHFT)) +#define LP8556_COMB2_CONFIG (LP8556_COMBINED2 << BRT_MODE_SHFT) + +/* ROM area boundary */ +#define EEPROM_START (0xA0) +#define EEPROM_END (0xA7) +#define EPROM_START (0xA0) +#define EPROM_END (0xAF) + +enum lp855x_chip_id { + LP8550, + LP8551, + LP8552, + LP8553, + LP8556, +}; + +enum lp855x_brightness_ctrl_mode { + PWM_BASED = 1, + REGISTER_BASED, +}; + +enum lp8550_brighntess_source { + LP8550_PWM_ONLY, + LP8550_I2C_ONLY = 2, +}; + +enum lp8551_brighntess_source { + LP8551_PWM_ONLY = LP8550_PWM_ONLY, + LP8551_I2C_ONLY = LP8550_I2C_ONLY, +}; + +enum lp8552_brighntess_source { + LP8552_PWM_ONLY = LP8550_PWM_ONLY, + LP8552_I2C_ONLY = LP8550_I2C_ONLY, +}; + +enum lp8553_brighntess_source { + LP8553_PWM_ONLY = LP8550_PWM_ONLY, + LP8553_I2C_ONLY = LP8550_I2C_ONLY, +}; + +enum lp8556_brightness_source { + LP8556_PWM_ONLY, + LP8556_COMBINED1, /* pwm + i2c before the shaper block */ + LP8556_I2C_ONLY, + LP8556_COMBINED2, /* pwm + i2c after the shaper block */ +}; + +struct lp855x_pwm_data { + void (*pwm_set_intensity) (int brightness, int max_brightness); + int (*pwm_get_intensity) (int max_brightness); +}; + +struct lp855x_rom_data { + u8 addr; + u8 val; +}; + +/** + * struct lp855x_platform_data + * @name : Backlight driver name. If it is not defined, default name is set. + * @mode : brightness control by pwm or lp855x register + * @device_control : value of DEVICE CONTROL register + * @initial_brightness : initial value of backlight brightness + * @pwm_data : platform specific pwm generation functions. + Only valid when mode is PWM_BASED. + * @load_new_rom_data : + 0 : use default configuration data + 1 : update values of eeprom or eprom registers on loading driver + * @size_program : total size of lp855x_rom_data + * @rom_data : list of new eeprom/eprom registers + */ +struct lp855x_platform_data { + char *name; + enum lp855x_brightness_ctrl_mode mode; + u8 device_control; + int initial_brightness; + struct lp855x_pwm_data pwm_data; + u8 load_new_rom_data; + int size_program; + struct lp855x_rom_data *rom_data; +}; + +#endif -- cgit v1.2.3 From c8df7428635c02ca3051e39179c83297d8b76fba Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Fri, 23 Mar 2012 15:02:02 -0700 Subject: backlight: add driver for Bachmann's ot200 Add backlight driver for Bachmann's ot200 visualisation device. The driver uses MFGPT 7 of CS5535 silicon to regulate the backlight. [akpm@linux-foundation.org: remove redundant test of `brightness'] Signed-off-by: Christian Gmeiner Cc: Lars-Peter Clausen Cc: Andres Salomon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 7 ++ drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/ot200_bl.c | 175 +++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 drivers/video/backlight/ot200_bl.c (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 49e7d83f869f..248d6c0858dd 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -341,6 +341,13 @@ config BACKLIGHT_LP855X This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556 backlight driver. +config BACKLIGHT_OT200 + tristate "Backlight driver for ot200 visualisation device" + depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT + help + To compile this driver as a module, choose M here: the module will be + called ot200_bl. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 0ee06e0832bd..c71dd793363d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -39,4 +39,4 @@ obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o - +obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c new file mode 100644 index 000000000000..f519d55a294c --- /dev/null +++ b/drivers/video/backlight/ot200_bl.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2012 Bachmann electronic GmbH + * Christian Gmeiner + * + * Backlight driver for ot200 visualisation device from + * Bachmann electronic GmbH. + * + * 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 +#include +#include +#include +#include + +static struct cs5535_mfgpt_timer *pwm_timer; + +/* this array defines the mapping of brightness in % to pwm frequency */ +static const u8 dim_table[101] = {0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 14, 15, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, + 30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 50, + 53, 55, 58, 61, 65, 68, 72, 75, 79, 84, 88, + 93, 97, 103, 108, 114, 120, 126, 133, 140, + 147, 155, 163}; + +struct ot200_backlight_data { + int current_brightness; +}; + +#define GPIO_DIMM 27 +#define SCALE 1 +#define CMP1MODE 0x2 /* compare on GE; output high on compare + * greater than or equal */ +#define PWM_SETUP (SCALE | CMP1MODE << 6 | MFGPT_SETUP_CNTEN) +#define MAX_COMP2 163 + +static int ot200_backlight_update_status(struct backlight_device *bl) +{ + struct ot200_backlight_data *data = bl_get_data(bl); + int brightness = bl->props.brightness; + + if (bl->props.state & BL_CORE_FBBLANK) + brightness = 0; + + /* enable or disable PWM timer */ + if (brightness == 0) + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, 0); + else if (data->current_brightness == 0) { + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0); + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, + MFGPT_SETUP_CNTEN); + } + + /* apply new brightness value */ + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1, + MAX_COMP2 - dim_table[brightness]); + data->current_brightness = brightness; + + return 0; +} + +static int ot200_backlight_get_brightness(struct backlight_device *bl) +{ + struct ot200_backlight_data *data = bl_get_data(bl); + return data->current_brightness; +} + +static const struct backlight_ops ot200_backlight_ops = { + .update_status = ot200_backlight_update_status, + .get_brightness = ot200_backlight_get_brightness, +}; + +static int ot200_backlight_probe(struct platform_device *pdev) +{ + struct backlight_device *bl; + struct ot200_backlight_data *data; + struct backlight_properties props; + int retval = 0; + + /* request gpio */ + if (gpio_request(GPIO_DIMM, "ot200 backlight dimmer") < 0) { + dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM); + return -ENODEV; + } + + /* request timer */ + 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; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + retval = -ENOMEM; + goto error_kzalloc; + } + + /* setup gpio */ + cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_ENABLE); + cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_AUX1); + + /* setup timer */ + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1, 0); + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP2, MAX_COMP2); + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, PWM_SETUP); + + data->current_brightness = 100; + props.max_brightness = 100; + props.brightness = 100; + props.type = BACKLIGHT_RAW; + + bl = backlight_device_register(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; + } + + platform_set_drvdata(pdev, bl); + + return 0; + +error_backlight_device_register: + kfree(data); +error_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); + cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1, + MAX_COMP2 - dim_table[100]); + + cs5535_mfgpt_free_timer(pwm_timer); + gpio_free(GPIO_DIMM); + + kfree(data); + return 0; +} + +static struct platform_driver ot200_backlight_driver = { + .driver = { + .name = "ot200-backlight", + .owner = THIS_MODULE, + }, + .probe = ot200_backlight_probe, + .remove = ot200_backlight_remove, +}; + +module_platform_driver(ot200_backlight_driver); + +MODULE_DESCRIPTION("backlight driver for ot200 visualisation device"); +MODULE_AUTHOR("Christian Gmeiner "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ot200-backlight"); -- cgit v1.2.3 From 35c1682cc069fc1f677012d3170757135e246b39 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Fri, 23 Mar 2012 15:02:02 -0700 Subject: backlight: add support for Pandora backlight Add support for pandora (openpandora.org) backlight. It might look like all this could be done using pwm_bl.c instead, but there is a need of special programming sequence when turning on the LED driver chip or else it will misbehave. Doing this using pwm_bl.c would require to use some register programming and pwm functions from platform code, and ARM maintainers are allergic to driver-like code in /arch/arm nowadays. The PMIC PWM driver is currently missing too, so pwm_bl.c can't be used anyway. Signed-off-by: Grazvydas Ignotas Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 7 ++ drivers/video/backlight/Makefile | 1 + drivers/video/backlight/pandora_bl.c | 171 +++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 drivers/video/backlight/pandora_bl.c (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 248d6c0858dd..ed68fde54454 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -348,6 +348,13 @@ config BACKLIGHT_OT200 To compile this driver as a module, choose M here: the module will be called ot200_bl. +config BACKLIGHT_PANDORA + tristate "Backlight driver for Pandora console" + depends on TWL4030_CORE + help + If you have a Pandora console, 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 c71dd793363d..8071eb656147 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_BACKLIGHT_HP680) += hp680_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 diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c new file mode 100644 index 000000000000..4ec30748b447 --- /dev/null +++ b/drivers/video/backlight/pandora_bl.c @@ -0,0 +1,171 @@ +/* + * Backlight driver for Pandora handheld. + * Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight. + * Based on pwm_bl.c + * + * Copyright 2009,2012 Gražvydas Ignotas + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define TWL_PWM0_ON 0x00 +#define TWL_PWM0_OFF 0x01 + +#define TWL_INTBR_GPBR1 0x0c +#define TWL_INTBR_PMBR1 0x0d + +#define TWL_PMBR1_PWM0_MUXMASK 0x0c +#define TWL_PMBR1_PWM0 0x04 +#define PWM0_CLK_ENABLE BIT(0) +#define PWM0_ENABLE BIT(2) + +/* range accepted by hardware */ +#define MIN_VALUE 9 +#define MAX_VALUE 63 +#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE) + +#define PANDORABL_WAS_OFF BL_CORE_DRIVER1 + +static int pandora_backlight_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + u8 r; + + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + if (bl->props.state & BL_CORE_FBBLANK) + brightness = 0; + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + if ((unsigned int)brightness > MAX_USER_VALUE) + brightness = MAX_USER_VALUE; + + if (brightness == 0) { + if (bl->props.state & PANDORABL_WAS_OFF) + goto done; + + /* first disable PWM0 output, then clock */ + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1); + r &= ~PWM0_ENABLE; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); + r &= ~PWM0_CLK_ENABLE; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); + + goto done; + } + + if (bl->props.state & PANDORABL_WAS_OFF) { + /* + * 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); + + /* first enable clock, then PWM0 out */ + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1); + r &= ~PWM0_ENABLE; + r |= PWM0_CLK_ENABLE; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); + r |= PWM0_ENABLE; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); + + /* + * TI made it very easy to enable digital control, so easy that + * it often triggers unintentionally and disabes PWM control, + * so wait until 1 wire mode detection window ends. + */ + usleep_range(2000, 10000); + } + + twl_i2c_write_u8(TWL4030_MODULE_PWM0, MIN_VALUE + brightness, + TWL_PWM0_OFF); + +done: + if (brightness != 0) + bl->props.state &= ~PANDORABL_WAS_OFF; + else + bl->props.state |= PANDORABL_WAS_OFF; + + return 0; +} + +static int pandora_backlight_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static const struct backlight_ops pandora_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = pandora_backlight_update_status, + .get_brightness = pandora_backlight_get_brightness, +}; + +static int pandora_backlight_probe(struct platform_device *pdev) +{ + struct backlight_properties props; + struct backlight_device *bl; + u8 r; + + 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); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } + + platform_set_drvdata(pdev, bl); + + /* 64 cycle period, ON position 0 */ + twl_i2c_write_u8(TWL4030_MODULE_PWM0, 0x80, TWL_PWM0_ON); + + bl->props.state |= PANDORABL_WAS_OFF; + bl->props.brightness = MAX_USER_VALUE; + backlight_update_status(bl); + + /* enable PWM function in pin mux */ + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_PMBR1); + r &= ~TWL_PMBR1_PWM0_MUXMASK; + r |= TWL_PMBR1_PWM0; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_PMBR1); + + 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); + +MODULE_AUTHOR("Gražvydas Ignotas "); +MODULE_DESCRIPTION("Pandora Backlight Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pandora-backlight"); -- cgit v1.2.3 From 67a67272e890c79372bc0e2e555071f903d864a7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 23 Mar 2012 15:02:02 -0700 Subject: backlight: convert platform_lcd to dev_pm_ops Instead of using legacy suspend/resume methods, using newer dev_pm_ops structure allows better control over power management. Signed-off-by: Jingoo Han Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/platform_lcd.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index f0bf491ed087..b6672340d6c7 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -121,9 +121,9 @@ static int __devexit platform_lcd_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st) +static int platform_lcd_suspend(struct device *dev) { - struct platform_lcd *plcd = platform_get_drvdata(pdev); + struct platform_lcd *plcd = dev_get_drvdata(dev); plcd->suspended = 1; platform_lcd_set_power(plcd->lcd, plcd->power); @@ -131,29 +131,30 @@ static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st) return 0; } -static int platform_lcd_resume(struct platform_device *pdev) +static int platform_lcd_resume(struct device *dev) { - struct platform_lcd *plcd = platform_get_drvdata(pdev); + struct platform_lcd *plcd = dev_get_drvdata(dev); plcd->suspended = 0; platform_lcd_set_power(plcd->lcd, plcd->power); return 0; } -#else -#define platform_lcd_suspend NULL -#define platform_lcd_resume NULL + +static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend, + platform_lcd_resume); #endif static struct platform_driver platform_lcd_driver = { .driver = { .name = "platform-lcd", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &platform_lcd_pm_ops, +#endif }, .probe = platform_lcd_probe, .remove = __devexit_p(platform_lcd_remove), - .suspend = platform_lcd_suspend, - .resume = platform_lcd_resume, }; module_platform_driver(platform_lcd_driver); -- cgit v1.2.3 From 2df5e12900d847af9113980d015939dde0d1b1d4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 23 Mar 2012 15:02:03 -0700 Subject: backlight: fix ot200_bl build Fix build error when GPIO_CS5535 is not enabled: drivers/built-in.o: In function `ot200_backlight_probe': ot200_bl.c:(.text+0x205bf): undefined reference to `cs5535_gpio_set' ot200_bl.c:(.text+0x205d1): undefined reference to `cs5535_gpio_set' Signed-off-by: Randy Dunlap Cc: Christian Gmeiner Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/backlight') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index ed68fde54454..7ed9991fa747 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -343,7 +343,7 @@ config BACKLIGHT_LP855X config BACKLIGHT_OT200 tristate "Backlight driver for ot200 visualisation device" - depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT + depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535 help To compile this driver as a module, choose M here: the module will be called ot200_bl. -- cgit v1.2.3