mc13783-pwrbutton.c (7387B)
1/* 2 * Copyright (C) 2011 Philippe Rétornaz 3 * 4 * Based on twl4030-pwrbutton driver by: 5 * Peter De Schrijver <peter.de-schrijver@nokia.com> 6 * Felipe Balbi <felipe.balbi@nokia.com> 7 * 8 * This file is subject to the terms and conditions of the GNU General 9 * Public License. See the file "COPYING" in the main directory of this 10 * archive for more details. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA 20 */ 21 22#include <linux/module.h> 23#include <linux/kernel.h> 24#include <linux/errno.h> 25#include <linux/input.h> 26#include <linux/interrupt.h> 27#include <linux/platform_device.h> 28#include <linux/mfd/mc13783.h> 29#include <linux/sched.h> 30#include <linux/slab.h> 31 32struct mc13783_pwrb { 33 struct input_dev *pwr; 34 struct mc13xxx *mc13783; 35#define MC13783_PWRB_B1_POL_INVERT (1 << 0) 36#define MC13783_PWRB_B2_POL_INVERT (1 << 1) 37#define MC13783_PWRB_B3_POL_INVERT (1 << 2) 38 int flags; 39 unsigned short keymap[3]; 40}; 41 42#define MC13783_REG_INTERRUPT_SENSE_1 5 43#define MC13783_IRQSENSE1_ONOFD1S (1 << 3) 44#define MC13783_IRQSENSE1_ONOFD2S (1 << 4) 45#define MC13783_IRQSENSE1_ONOFD3S (1 << 5) 46 47#define MC13783_REG_POWER_CONTROL_2 15 48#define MC13783_POWER_CONTROL_2_ON1BDBNC 4 49#define MC13783_POWER_CONTROL_2_ON2BDBNC 6 50#define MC13783_POWER_CONTROL_2_ON3BDBNC 8 51#define MC13783_POWER_CONTROL_2_ON1BRSTEN (1 << 1) 52#define MC13783_POWER_CONTROL_2_ON2BRSTEN (1 << 2) 53#define MC13783_POWER_CONTROL_2_ON3BRSTEN (1 << 3) 54 55static irqreturn_t button_irq(int irq, void *_priv) 56{ 57 struct mc13783_pwrb *priv = _priv; 58 int val; 59 60 mc13xxx_irq_ack(priv->mc13783, irq); 61 mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val); 62 63 switch (irq) { 64 case MC13783_IRQ_ONOFD1: 65 val = val & MC13783_IRQSENSE1_ONOFD1S ? 1 : 0; 66 if (priv->flags & MC13783_PWRB_B1_POL_INVERT) 67 val ^= 1; 68 input_report_key(priv->pwr, priv->keymap[0], val); 69 break; 70 71 case MC13783_IRQ_ONOFD2: 72 val = val & MC13783_IRQSENSE1_ONOFD2S ? 1 : 0; 73 if (priv->flags & MC13783_PWRB_B2_POL_INVERT) 74 val ^= 1; 75 input_report_key(priv->pwr, priv->keymap[1], val); 76 break; 77 78 case MC13783_IRQ_ONOFD3: 79 val = val & MC13783_IRQSENSE1_ONOFD3S ? 1 : 0; 80 if (priv->flags & MC13783_PWRB_B3_POL_INVERT) 81 val ^= 1; 82 input_report_key(priv->pwr, priv->keymap[2], val); 83 break; 84 } 85 86 input_sync(priv->pwr); 87 88 return IRQ_HANDLED; 89} 90 91static int mc13783_pwrbutton_probe(struct platform_device *pdev) 92{ 93 const struct mc13xxx_buttons_platform_data *pdata; 94 struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); 95 struct input_dev *pwr; 96 struct mc13783_pwrb *priv; 97 int err = 0; 98 int reg = 0; 99 100 pdata = dev_get_platdata(&pdev->dev); 101 if (!pdata) { 102 dev_err(&pdev->dev, "missing platform data\n"); 103 return -ENODEV; 104 } 105 106 pwr = input_allocate_device(); 107 if (!pwr) { 108 dev_dbg(&pdev->dev, "Can't allocate power button\n"); 109 return -ENOMEM; 110 } 111 112 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 113 if (!priv) { 114 err = -ENOMEM; 115 dev_dbg(&pdev->dev, "Can't allocate power button\n"); 116 goto free_input_dev; 117 } 118 119 reg |= (pdata->b1on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON1BDBNC; 120 reg |= (pdata->b2on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON2BDBNC; 121 reg |= (pdata->b3on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON3BDBNC; 122 123 priv->pwr = pwr; 124 priv->mc13783 = mc13783; 125 126 mc13xxx_lock(mc13783); 127 128 if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) { 129 priv->keymap[0] = pdata->b1on_key; 130 if (pdata->b1on_key != KEY_RESERVED) 131 __set_bit(pdata->b1on_key, pwr->keybit); 132 133 if (pdata->b1on_flags & MC13783_BUTTON_POL_INVERT) 134 priv->flags |= MC13783_PWRB_B1_POL_INVERT; 135 136 if (pdata->b1on_flags & MC13783_BUTTON_RESET_EN) 137 reg |= MC13783_POWER_CONTROL_2_ON1BRSTEN; 138 139 err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD1, 140 button_irq, "b1on", priv); 141 if (err) { 142 dev_dbg(&pdev->dev, "Can't request irq\n"); 143 goto free_priv; 144 } 145 } 146 147 if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) { 148 priv->keymap[1] = pdata->b2on_key; 149 if (pdata->b2on_key != KEY_RESERVED) 150 __set_bit(pdata->b2on_key, pwr->keybit); 151 152 if (pdata->b2on_flags & MC13783_BUTTON_POL_INVERT) 153 priv->flags |= MC13783_PWRB_B2_POL_INVERT; 154 155 if (pdata->b2on_flags & MC13783_BUTTON_RESET_EN) 156 reg |= MC13783_POWER_CONTROL_2_ON2BRSTEN; 157 158 err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD2, 159 button_irq, "b2on", priv); 160 if (err) { 161 dev_dbg(&pdev->dev, "Can't request irq\n"); 162 goto free_irq_b1; 163 } 164 } 165 166 if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) { 167 priv->keymap[2] = pdata->b3on_key; 168 if (pdata->b3on_key != KEY_RESERVED) 169 __set_bit(pdata->b3on_key, pwr->keybit); 170 171 if (pdata->b3on_flags & MC13783_BUTTON_POL_INVERT) 172 priv->flags |= MC13783_PWRB_B3_POL_INVERT; 173 174 if (pdata->b3on_flags & MC13783_BUTTON_RESET_EN) 175 reg |= MC13783_POWER_CONTROL_2_ON3BRSTEN; 176 177 err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD3, 178 button_irq, "b3on", priv); 179 if (err) { 180 dev_dbg(&pdev->dev, "Can't request irq: %d\n", err); 181 goto free_irq_b2; 182 } 183 } 184 185 mc13xxx_reg_rmw(mc13783, MC13783_REG_POWER_CONTROL_2, 0x3FE, reg); 186 187 mc13xxx_unlock(mc13783); 188 189 pwr->name = "mc13783_pwrbutton"; 190 pwr->phys = "mc13783_pwrbutton/input0"; 191 pwr->dev.parent = &pdev->dev; 192 193 pwr->keycode = priv->keymap; 194 pwr->keycodemax = ARRAY_SIZE(priv->keymap); 195 pwr->keycodesize = sizeof(priv->keymap[0]); 196 __set_bit(EV_KEY, pwr->evbit); 197 198 err = input_register_device(pwr); 199 if (err) { 200 dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); 201 goto free_irq; 202 } 203 204 platform_set_drvdata(pdev, priv); 205 206 return 0; 207 208free_irq: 209 mc13xxx_lock(mc13783); 210 211 if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) 212 mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD3, priv); 213 214free_irq_b2: 215 if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) 216 mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD2, priv); 217 218free_irq_b1: 219 if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) 220 mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD1, priv); 221 222free_priv: 223 mc13xxx_unlock(mc13783); 224 kfree(priv); 225 226free_input_dev: 227 input_free_device(pwr); 228 229 return err; 230} 231 232static int mc13783_pwrbutton_remove(struct platform_device *pdev) 233{ 234 struct mc13783_pwrb *priv = platform_get_drvdata(pdev); 235 const struct mc13xxx_buttons_platform_data *pdata; 236 237 pdata = dev_get_platdata(&pdev->dev); 238 239 mc13xxx_lock(priv->mc13783); 240 241 if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) 242 mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD3, priv); 243 if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) 244 mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD2, priv); 245 if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) 246 mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD1, priv); 247 248 mc13xxx_unlock(priv->mc13783); 249 250 input_unregister_device(priv->pwr); 251 kfree(priv); 252 253 return 0; 254} 255 256static struct platform_driver mc13783_pwrbutton_driver = { 257 .probe = mc13783_pwrbutton_probe, 258 .remove = mc13783_pwrbutton_remove, 259 .driver = { 260 .name = "mc13783-pwrbutton", 261 }, 262}; 263 264module_platform_driver(mc13783_pwrbutton_driver); 265 266MODULE_ALIAS("platform:mc13783-pwrbutton"); 267MODULE_DESCRIPTION("MC13783 Power Button"); 268MODULE_LICENSE("GPL v2"); 269MODULE_AUTHOR("Philippe Retornaz");