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.13-rc3 190 lines 4.9 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 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 = devm_kzalloc(&pdev->dev, sizeof(*gpio_charger), 90 GFP_KERNEL); 91 if (!gpio_charger) { 92 dev_err(&pdev->dev, "Failed to alloc driver structure\n"); 93 return -ENOMEM; 94 } 95 96 charger = &gpio_charger->charger; 97 98 charger->name = pdata->name ? pdata->name : "gpio-charger"; 99 charger->type = pdata->type; 100 charger->properties = gpio_charger_properties; 101 charger->num_properties = ARRAY_SIZE(gpio_charger_properties); 102 charger->get_property = gpio_charger_get_property; 103 charger->supplied_to = pdata->supplied_to; 104 charger->num_supplicants = pdata->num_supplicants; 105 106 ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); 107 if (ret) { 108 dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); 109 goto err_free; 110 } 111 ret = gpio_direction_input(pdata->gpio); 112 if (ret) { 113 dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); 114 goto err_gpio_free; 115 } 116 117 gpio_charger->pdata = pdata; 118 119 ret = power_supply_register(&pdev->dev, charger); 120 if (ret < 0) { 121 dev_err(&pdev->dev, "Failed to register power supply: %d\n", 122 ret); 123 goto err_gpio_free; 124 } 125 126 irq = gpio_to_irq(pdata->gpio); 127 if (irq > 0) { 128 ret = request_any_context_irq(irq, gpio_charger_irq, 129 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 130 dev_name(&pdev->dev), charger); 131 if (ret < 0) 132 dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret); 133 else 134 gpio_charger->irq = irq; 135 } 136 137 platform_set_drvdata(pdev, gpio_charger); 138 139 return 0; 140 141err_gpio_free: 142 gpio_free(pdata->gpio); 143err_free: 144 return ret; 145} 146 147static int 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 return 0; 159} 160 161#ifdef CONFIG_PM_SLEEP 162static int gpio_charger_resume(struct device *dev) 163{ 164 struct platform_device *pdev = to_platform_device(dev); 165 struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); 166 167 power_supply_changed(&gpio_charger->charger); 168 169 return 0; 170} 171#endif 172 173static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume); 174 175static struct platform_driver gpio_charger_driver = { 176 .probe = gpio_charger_probe, 177 .remove = gpio_charger_remove, 178 .driver = { 179 .name = "gpio-charger", 180 .owner = THIS_MODULE, 181 .pm = &gpio_charger_pm_ops, 182 }, 183}; 184 185module_platform_driver(gpio_charger_driver); 186 187MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 188MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); 189MODULE_LICENSE("GPL"); 190MODULE_ALIAS("platform:gpio-charger");