platform_lcd.c revision e958d3ace7791f33518f0259cd3cf229408b135c
1c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks/* drivers/video/backlight/platform_lcd.c 2c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * 3c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * Copyright 2008 Simtec Electronics 4c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * Ben Dooks <ben@simtec.co.uk> 5c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * 6c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * Generic platform-device LCD power control interface. 7c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * 8c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * This program is free software; you can redistribute it and/or modify 9c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * it under the terms of the GNU General Public License version 2 as 10c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * published by the Free Software Foundation. 11c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks * 12c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks*/ 13c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 14c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#include <linux/module.h> 15c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#include <linux/platform_device.h> 16c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#include <linux/fb.h> 17c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#include <linux/backlight.h> 18c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#include <linux/lcd.h> 19c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 20c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#include <video/platform_lcd.h> 21c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 22c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstruct platform_lcd { 23c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct device *us; 24c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct lcd_device *lcd; 25c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct plat_lcd_data *pdata; 26c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 27c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks unsigned int power; 28c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks unsigned int suspended : 1; 29c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks}; 30c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 31c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic inline struct platform_lcd *to_our_lcd(struct lcd_device *lcd) 32c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 33c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return lcd_get_data(lcd); 34c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 35c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 36c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int platform_lcd_get_power(struct lcd_device *lcd) 37c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 38c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd = to_our_lcd(lcd); 39c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 40c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return plcd->power; 41c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 42c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 43c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int platform_lcd_set_power(struct lcd_device *lcd, int power) 44c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 45c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd = to_our_lcd(lcd); 46c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks int lcd_power = 1; 47c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 48c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks if (power == FB_BLANK_POWERDOWN || plcd->suspended) 49c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks lcd_power = 0; 50c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 51c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd->pdata->set_power(plcd->pdata, lcd_power); 52c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd->power = power; 53c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 54c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return 0; 55c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 56c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 57c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int platform_lcd_match(struct lcd_device *lcd, struct fb_info *info) 58c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 59c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd = to_our_lcd(lcd); 60c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct plat_lcd_data *pdata = plcd->pdata; 61c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 62c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks if (pdata->match_fb) 63c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return pdata->match_fb(pdata, info); 64c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 65c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return plcd->us->parent == info->device; 66c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 67c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 68c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic struct lcd_ops platform_lcd_ops = { 69c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .get_power = platform_lcd_get_power, 70c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .set_power = platform_lcd_set_power, 71c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .check_fb = platform_lcd_match, 72c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks}; 73c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 74c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int __devinit platform_lcd_probe(struct platform_device *pdev) 75c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 76c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct plat_lcd_data *pdata; 77c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd; 78c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct device *dev = &pdev->dev; 79c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks int err; 80c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 81c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks pdata = pdev->dev.platform_data; 82c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks if (!pdata) { 83c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks dev_err(dev, "no platform data supplied\n"); 84c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return -EINVAL; 85c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks } 86c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 87c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd = kzalloc(sizeof(struct platform_lcd), GFP_KERNEL); 88c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks if (!plcd) { 89c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks dev_err(dev, "no memory for state\n"); 90c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return -ENOMEM; 91c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks } 92c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 93c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd->us = dev; 94c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd->pdata = pdata; 95e958d3ace7791f33518f0259cd3cf229408b135cBen Dooks plcd->lcd = lcd_device_register(dev_name(dev), dev, 96c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd, &platform_lcd_ops); 97c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks if (IS_ERR(plcd->lcd)) { 98c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks dev_err(dev, "cannot register lcd device\n"); 99c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks err = PTR_ERR(plcd->lcd); 100c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks goto err_mem; 101c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks } 102c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 103c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks platform_set_drvdata(pdev, plcd); 104c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return 0; 105c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 106c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks err_mem: 107c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks kfree(plcd); 108c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return err; 109c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 110c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 111c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int __devexit platform_lcd_remove(struct platform_device *pdev) 112c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 113c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd = platform_get_drvdata(pdev); 114c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 115c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks lcd_device_unregister(plcd->lcd); 116c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks kfree(plcd); 117c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 118c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return 0; 119c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 120c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 121c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#ifdef CONFIG_PM 122c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st) 123c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 124c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd = platform_get_drvdata(pdev); 125c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 126c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd->suspended = 1; 127c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks platform_lcd_set_power(plcd->lcd, plcd->power); 128c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 129c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return 0; 130c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 131c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 132c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int platform_lcd_resume(struct platform_device *pdev) 133c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 134c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks struct platform_lcd *plcd = platform_get_drvdata(pdev); 135c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 136c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks plcd->suspended = 0; 137c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks platform_lcd_set_power(plcd->lcd, plcd->power); 138c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 139c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return 0; 140c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 141c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#else 142c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#define platform_lcd_suspend NULL 143c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#define platform_lcd_resume NULL 144c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks#endif 145c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 146c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic struct platform_driver platform_lcd_driver = { 147c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .driver = { 148c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .name = "platform-lcd", 149c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .owner = THIS_MODULE, 150c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks }, 151c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .probe = platform_lcd_probe, 152c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .remove = __devexit_p(platform_lcd_remove), 153c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .suspend = platform_lcd_suspend, 154c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks .resume = platform_lcd_resume, 155c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks}; 156c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 157c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic int __init platform_lcd_init(void) 158c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 159c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks return platform_driver_register(&platform_lcd_driver); 160c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 161c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 162c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksstatic void __exit platform_lcd_cleanup(void) 163c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks{ 164c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks platform_driver_unregister(&platform_lcd_driver); 165c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks} 166c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 167c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksmodule_init(platform_lcd_init); 168c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooksmodule_exit(platform_lcd_cleanup); 169c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben Dooks 170c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben DooksMODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); 171c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben DooksMODULE_LICENSE("GPL v2"); 172c25826a7cf1c61b5c6e6db8365172eb97ef39ef3Ben DooksMODULE_ALIAS("platform:platform-lcd"); 173