1/* 2 * drivers/video/backlight/ubicom32lcdpowerpower.c 3 * LCD power driver for the Ubicom32 platform 4 * 5 * (C) Copyright 2009, Ubicom, Inc. 6 * 7 * This file is part of the Ubicom32 Linux Kernel Port. 8 * 9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute 10 * it and/or modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation, either version 2 of the 12 * License, or (at your option) any later version. 13 * 14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it 15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied 16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with the Ubicom32 Linux Kernel Port. If not, 21 * see <http://www.gnu.org/licenses/>. 22 * 23 * Ubicom32 implementation derived from (with many thanks): 24 * arch/m68knommu 25 * arch/blackfin 26 * arch/parisc 27 */ 28#include <linux/init.h> 29#include <linux/kernel.h> 30#include <linux/module.h> 31#include <linux/platform_device.h> 32#include <linux/lcd.h> 33#include <linux/fb.h> 34#include <linux/gpio.h> 35 36#include <asm/ubicom32lcdpower.h> 37#include <asm/ip5000.h> 38 39#define DRIVER_NAME "ubicom32lcdpower" 40 41struct ubicom32lcdpower_data { 42 /* 43 * Pointer to the platform data structure. Keep this around since we need values 44 * from it to set the backlight intensity. 45 */ 46 const struct ubicom32lcdpower_platform_data *pdata; 47 48 /* 49 * LCD device, we have to save this for use when we remove ourselves. 50 */ 51 struct lcd_device *lcddev; 52}; 53 54/* 55 * ubicom32lcdpower_set_power 56 */ 57static int ubicom32lcdpower_set_power(struct lcd_device *ld, int power) 58{ 59 struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld); 60 if (power == FB_BLANK_UNBLANK) { 61 gpio_direction_output(ud->pdata->vgh_gpio, ud->pdata->vgh_polarity); 62 return 0; 63 } 64 65 gpio_direction_output(ud->pdata->vgh_gpio, !ud->pdata->vgh_polarity); 66 return 0; 67} 68 69/* 70 * ubicom32lcdpower_get_power 71 */ 72static int ubicom32lcdpower_get_power(struct lcd_device *ld) 73{ 74 struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld); 75 int vgh = gpio_get_value(ud->pdata->vgh_gpio); 76 if ((vgh && ud->pdata->vgh_polarity) || (!vgh && !ud->pdata->vgh_polarity)) { 77 return 1; 78 } 79 80 return 0; 81} 82 83static struct lcd_ops ubicom32lcdpower_ops = { 84 .get_power = ubicom32lcdpower_get_power, 85 .set_power = ubicom32lcdpower_set_power, 86}; 87 88/* 89 * ubicom32lcdpower_probe 90 */ 91static int ubicom32lcdpower_probe(struct platform_device *pdev) 92{ 93 const struct ubicom32lcdpower_platform_data *pdata = pdev->dev.platform_data; 94 struct ubicom32lcdpower_data *ud; 95 struct lcd_device *lcddev; 96 int retval; 97 98 /* 99 * Check to see if we have any platform data, if we don't have a LCD to control 100 */ 101 if (!pdata) { 102 return -ENODEV; 103 } 104 105 /* 106 * Allocate our private data 107 */ 108 ud = kzalloc(sizeof(struct ubicom32lcdpower_data), GFP_KERNEL); 109 if (!ud) { 110 return -ENOMEM; 111 } 112 113 ud->pdata = pdata; 114 115 /* 116 * Request our GPIOs 117 */ 118 retval = gpio_request(pdata->vgh_gpio, "vgh"); 119 if (retval) { 120 dev_err(&pdev->dev, "Failed to allocate vgh GPIO\n"); 121 goto fail_gpio; 122 } 123 124 /* 125 * Register our lcd device 126 */ 127 lcddev = lcd_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32lcdpower_ops); 128 if (IS_ERR(lcddev)) { 129 retval = PTR_ERR(lcddev); 130 goto fail; 131 } 132 133 ud->lcddev = lcddev; 134 platform_set_drvdata(pdev, ud); 135 136 ubicom32lcdpower_set_power(lcddev, FB_BLANK_UNBLANK); 137 138 printk(KERN_INFO DRIVER_NAME ": LCD driver started\n"); 139 140 return 0; 141 142fail: 143 gpio_free(pdata->vgh_gpio); 144 145fail_gpio: 146 platform_set_drvdata(pdev, NULL); 147 kfree(ud); 148 return retval; 149} 150 151/* 152 * ubicom32lcdpower_remove 153 */ 154static int __exit ubicom32lcdpower_remove(struct platform_device *pdev) 155{ 156 struct ubicom32lcdpower_data *ud = platform_get_drvdata(pdev); 157 158 lcd_device_unregister(ud->lcddev); 159 platform_set_drvdata(pdev, NULL); 160 kfree(ud); 161 162 return 0; 163} 164 165static struct platform_driver ubicom32lcdpower_driver = { 166 .driver = { 167 .name = DRIVER_NAME, 168 .owner = THIS_MODULE, 169 }, 170 171 .remove = __exit_p(ubicom32lcdpower_remove), 172}; 173 174/* 175 * ubicom32lcdpower_init 176 */ 177static int __init ubicom32lcdpower_init(void) 178{ 179 return platform_driver_probe(&ubicom32lcdpower_driver, ubicom32lcdpower_probe); 180} 181module_init(ubicom32lcdpower_init); 182 183/* 184 * ubicom32lcdpower_exit 185 */ 186static void __exit ubicom32lcdpower_exit(void) 187{ 188 platform_driver_unregister(&ubicom32lcdpower_driver); 189} 190module_exit(ubicom32lcdpower_exit); 191 192MODULE_AUTHOR("Patrick Tjin <@ubicom.com>"); 193MODULE_DESCRIPTION("Ubicom32 lcd power driver"); 194MODULE_LICENSE("GPL"); 195