Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc4 193 lines 5.0 kB view raw
1/* 2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 3 * Driver for chargers which report their online status through a GPIO pin 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 * You should have received a copy of the GNU General Public License along 11 * with this program; if not, write to the Free Software Foundation, Inc., 12 * 675 Mass Ave, Cambridge, MA 02139, USA. 13 * 14 */ 15 16#include <linux/device.h> 17#include <linux/gpio.h> 18#include <linux/init.h> 19#include <linux/interrupt.h> 20#include <linux/kernel.h> 21#include <linux/module.h> 22#include <linux/platform_device.h> 23#include <linux/power_supply.h> 24#include <linux/slab.h> 25 26#include <linux/power/gpio-charger.h> 27 28struct gpio_charger { 29 const struct gpio_charger_platform_data *pdata; 30 unsigned int irq; 31 32 struct power_supply charger; 33}; 34 35static irqreturn_t gpio_charger_irq(int irq, void *devid) 36{ 37 struct power_supply *charger = devid; 38 39 power_supply_changed(charger); 40 41 return IRQ_HANDLED; 42} 43 44static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy) 45{ 46 return container_of(psy, struct gpio_charger, charger); 47} 48 49static int gpio_charger_get_property(struct power_supply *psy, 50 enum power_supply_property psp, union power_supply_propval *val) 51{ 52 struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); 53 const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; 54 55 switch (psp) { 56 case POWER_SUPPLY_PROP_ONLINE: 57 val->intval = gpio_get_value_cansleep(pdata->gpio); 58 val->intval ^= pdata->gpio_active_low; 59 break; 60 default: 61 return -EINVAL; 62 } 63 64 return 0; 65} 66 67static enum power_supply_property gpio_charger_properties[] = { 68 POWER_SUPPLY_PROP_ONLINE, 69}; 70 71static int __devinit gpio_charger_probe(struct platform_device *pdev) 72{ 73 const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; 74 struct gpio_charger *gpio_charger; 75 struct power_supply *charger; 76 int ret; 77 int irq; 78 79 if (!pdata) { 80 dev_err(&pdev->dev, "No platform data\n"); 81 return -EINVAL; 82 } 83 84 if (!gpio_is_valid(pdata->gpio)) { 85 dev_err(&pdev->dev, "Invalid gpio pin\n"); 86 return -EINVAL; 87 } 88 89 gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); 90 if (!gpio_charger) { 91 dev_err(&pdev->dev, "Failed to alloc driver structure\n"); 92 return -ENOMEM; 93 } 94 95 charger = &gpio_charger->charger; 96 97 charger->name = pdata->name ? pdata->name : "gpio-charger"; 98 charger->type = pdata->type; 99 charger->properties = gpio_charger_properties; 100 charger->num_properties = ARRAY_SIZE(gpio_charger_properties); 101 charger->get_property = gpio_charger_get_property; 102 charger->supplied_to = pdata->supplied_to; 103 charger->num_supplicants = pdata->num_supplicants; 104 105 ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); 106 if (ret) { 107 dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); 108 goto err_free; 109 } 110 ret = gpio_direction_input(pdata->gpio); 111 if (ret) { 112 dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); 113 goto err_gpio_free; 114 } 115 116 gpio_charger->pdata = pdata; 117 118 ret = power_supply_register(&pdev->dev, charger); 119 if (ret < 0) { 120 dev_err(&pdev->dev, "Failed to register power supply: %d\n", 121 ret); 122 goto err_gpio_free; 123 } 124 125 irq = gpio_to_irq(pdata->gpio); 126 if (irq > 0) { 127 ret = request_any_context_irq(irq, gpio_charger_irq, 128 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 129 dev_name(&pdev->dev), charger); 130 if (ret < 0) 131 dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret); 132 else 133 gpio_charger->irq = irq; 134 } 135 136 platform_set_drvdata(pdev, gpio_charger); 137 138 return 0; 139 140err_gpio_free: 141 gpio_free(pdata->gpio); 142err_free: 143 kfree(gpio_charger); 144 return ret; 145} 146 147static int __devexit gpio_charger_remove(struct platform_device *pdev) 148{ 149 struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); 150 151 if (gpio_charger->irq) 152 free_irq(gpio_charger->irq, &gpio_charger->charger); 153 154 power_supply_unregister(&gpio_charger->charger); 155 156 gpio_free(gpio_charger->pdata->gpio); 157 158 platform_set_drvdata(pdev, NULL); 159 kfree(gpio_charger); 160 161 return 0; 162} 163 164#ifdef CONFIG_PM_SLEEP 165static int gpio_charger_resume(struct device *dev) 166{ 167 struct platform_device *pdev = to_platform_device(dev); 168 struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); 169 170 power_supply_changed(&gpio_charger->charger); 171 172 return 0; 173} 174#endif 175 176static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume); 177 178static struct platform_driver gpio_charger_driver = { 179 .probe = gpio_charger_probe, 180 .remove = __devexit_p(gpio_charger_remove), 181 .driver = { 182 .name = "gpio-charger", 183 .owner = THIS_MODULE, 184 .pm = &gpio_charger_pm_ops, 185 }, 186}; 187 188module_platform_driver(gpio_charger_driver); 189 190MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 191MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); 192MODULE_LICENSE("GPL"); 193MODULE_ALIAS("platform:gpio-charger");