1fba65fe0SMichael Hennerich /* 2fba65fe0SMichael Hennerich * Keypad driver for Analog Devices ADP5520 MFD PMICs 3fba65fe0SMichael Hennerich * 4fba65fe0SMichael Hennerich * Copyright 2009 Analog Devices Inc. 5fba65fe0SMichael Hennerich * 6fba65fe0SMichael Hennerich * Licensed under the GPL-2 or later. 7fba65fe0SMichael Hennerich */ 8fba65fe0SMichael Hennerich 9fba65fe0SMichael Hennerich #include <linux/module.h> 10fba65fe0SMichael Hennerich #include <linux/kernel.h> 11fba65fe0SMichael Hennerich #include <linux/platform_device.h> 12fba65fe0SMichael Hennerich #include <linux/input.h> 13fba65fe0SMichael Hennerich #include <linux/mfd/adp5520.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 15*ec62c7a8SHimangi Saraogi #include <linux/device.h> 16fba65fe0SMichael Hennerich 17fba65fe0SMichael Hennerich struct adp5520_keys { 18fba65fe0SMichael Hennerich struct input_dev *input; 19fba65fe0SMichael Hennerich struct notifier_block notifier; 20fba65fe0SMichael Hennerich struct device *master; 21fba65fe0SMichael Hennerich unsigned short keycode[ADP5520_KEYMAPSIZE]; 22fba65fe0SMichael Hennerich }; 23fba65fe0SMichael Hennerich 24fba65fe0SMichael Hennerich static void adp5520_keys_report_event(struct adp5520_keys *dev, 25fba65fe0SMichael Hennerich unsigned short keymask, int value) 26fba65fe0SMichael Hennerich { 27fba65fe0SMichael Hennerich int i; 28fba65fe0SMichael Hennerich 29fba65fe0SMichael Hennerich for (i = 0; i < ADP5520_MAXKEYS; i++) 30fba65fe0SMichael Hennerich if (keymask & (1 << i)) 31fba65fe0SMichael Hennerich input_report_key(dev->input, dev->keycode[i], value); 32fba65fe0SMichael Hennerich 33fba65fe0SMichael Hennerich input_sync(dev->input); 34fba65fe0SMichael Hennerich } 35fba65fe0SMichael Hennerich 36fba65fe0SMichael Hennerich static int adp5520_keys_notifier(struct notifier_block *nb, 37fba65fe0SMichael Hennerich unsigned long event, void *data) 38fba65fe0SMichael Hennerich { 39fba65fe0SMichael Hennerich struct adp5520_keys *dev; 40fba65fe0SMichael Hennerich uint8_t reg_val_lo, reg_val_hi; 41fba65fe0SMichael Hennerich unsigned short keymask; 42fba65fe0SMichael Hennerich 43fba65fe0SMichael Hennerich dev = container_of(nb, struct adp5520_keys, notifier); 44fba65fe0SMichael Hennerich 45fba65fe0SMichael Hennerich if (event & ADP5520_KP_INT) { 46fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, ®_val_lo); 47fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, ®_val_hi); 48fba65fe0SMichael Hennerich 49fba65fe0SMichael Hennerich keymask = (reg_val_hi << 8) | reg_val_lo; 50fba65fe0SMichael Hennerich /* Read twice to clear */ 51fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, ®_val_lo); 52fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, ®_val_hi); 53fba65fe0SMichael Hennerich keymask |= (reg_val_hi << 8) | reg_val_lo; 54fba65fe0SMichael Hennerich adp5520_keys_report_event(dev, keymask, 1); 55fba65fe0SMichael Hennerich } 56fba65fe0SMichael Hennerich 57fba65fe0SMichael Hennerich if (event & ADP5520_KR_INT) { 58fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, ®_val_lo); 59fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, ®_val_hi); 60fba65fe0SMichael Hennerich 61fba65fe0SMichael Hennerich keymask = (reg_val_hi << 8) | reg_val_lo; 62fba65fe0SMichael Hennerich /* Read twice to clear */ 63fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, ®_val_lo); 64fba65fe0SMichael Hennerich adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, ®_val_hi); 65fba65fe0SMichael Hennerich keymask |= (reg_val_hi << 8) | reg_val_lo; 66fba65fe0SMichael Hennerich adp5520_keys_report_event(dev, keymask, 0); 67fba65fe0SMichael Hennerich } 68fba65fe0SMichael Hennerich 69fba65fe0SMichael Hennerich return 0; 70fba65fe0SMichael Hennerich } 71fba65fe0SMichael Hennerich 725298cc4cSBill Pemberton static int adp5520_keys_probe(struct platform_device *pdev) 73fba65fe0SMichael Hennerich { 74c838cb3dSJingoo Han struct adp5520_keys_platform_data *pdata = dev_get_platdata(&pdev->dev); 75fba65fe0SMichael Hennerich struct input_dev *input; 76fba65fe0SMichael Hennerich struct adp5520_keys *dev; 77fba65fe0SMichael Hennerich int ret, i; 78fba65fe0SMichael Hennerich unsigned char en_mask, ctl_mask = 0; 79fba65fe0SMichael Hennerich 80fba65fe0SMichael Hennerich if (pdev->id != ID_ADP5520) { 81fba65fe0SMichael Hennerich dev_err(&pdev->dev, "only ADP5520 supports Keypad\n"); 82fba65fe0SMichael Hennerich return -EINVAL; 83fba65fe0SMichael Hennerich } 84fba65fe0SMichael Hennerich 85*ec62c7a8SHimangi Saraogi if (!pdata) { 86fba65fe0SMichael Hennerich dev_err(&pdev->dev, "missing platform data\n"); 87fba65fe0SMichael Hennerich return -EINVAL; 88fba65fe0SMichael Hennerich } 89fba65fe0SMichael Hennerich 90fba65fe0SMichael Hennerich if (!(pdata->rows_en_mask && pdata->cols_en_mask)) 91fba65fe0SMichael Hennerich return -EINVAL; 92fba65fe0SMichael Hennerich 93*ec62c7a8SHimangi Saraogi dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 94*ec62c7a8SHimangi Saraogi if (!dev) { 95fba65fe0SMichael Hennerich dev_err(&pdev->dev, "failed to alloc memory\n"); 96fba65fe0SMichael Hennerich return -ENOMEM; 97fba65fe0SMichael Hennerich } 98fba65fe0SMichael Hennerich 99*ec62c7a8SHimangi Saraogi input = devm_input_allocate_device(&pdev->dev); 100*ec62c7a8SHimangi Saraogi if (!input) 101*ec62c7a8SHimangi Saraogi return -ENOMEM; 102fba65fe0SMichael Hennerich 103fba65fe0SMichael Hennerich dev->master = pdev->dev.parent; 104fba65fe0SMichael Hennerich dev->input = input; 105fba65fe0SMichael Hennerich 106fba65fe0SMichael Hennerich input->name = pdev->name; 107fba65fe0SMichael Hennerich input->phys = "adp5520-keys/input0"; 108fba65fe0SMichael Hennerich input->dev.parent = &pdev->dev; 109fba65fe0SMichael Hennerich 110fba65fe0SMichael Hennerich input_set_drvdata(input, dev); 111fba65fe0SMichael Hennerich 112fba65fe0SMichael Hennerich input->id.bustype = BUS_I2C; 113fba65fe0SMichael Hennerich input->id.vendor = 0x0001; 114fba65fe0SMichael Hennerich input->id.product = 0x5520; 115fba65fe0SMichael Hennerich input->id.version = 0x0001; 116fba65fe0SMichael Hennerich 117fba65fe0SMichael Hennerich input->keycodesize = sizeof(dev->keycode[0]); 118fba65fe0SMichael Hennerich input->keycodemax = pdata->keymapsize; 119fba65fe0SMichael Hennerich input->keycode = dev->keycode; 120fba65fe0SMichael Hennerich 121fba65fe0SMichael Hennerich memcpy(dev->keycode, pdata->keymap, 122fba65fe0SMichael Hennerich pdata->keymapsize * input->keycodesize); 123fba65fe0SMichael Hennerich 124fba65fe0SMichael Hennerich /* setup input device */ 125fba65fe0SMichael Hennerich __set_bit(EV_KEY, input->evbit); 126fba65fe0SMichael Hennerich 127fba65fe0SMichael Hennerich if (pdata->repeat) 128fba65fe0SMichael Hennerich __set_bit(EV_REP, input->evbit); 129fba65fe0SMichael Hennerich 130fba65fe0SMichael Hennerich for (i = 0; i < input->keycodemax; i++) 131fba65fe0SMichael Hennerich __set_bit(dev->keycode[i], input->keybit); 132fba65fe0SMichael Hennerich __clear_bit(KEY_RESERVED, input->keybit); 133fba65fe0SMichael Hennerich 134fba65fe0SMichael Hennerich ret = input_register_device(input); 135fba65fe0SMichael Hennerich if (ret) { 136fba65fe0SMichael Hennerich dev_err(&pdev->dev, "unable to register input device\n"); 137*ec62c7a8SHimangi Saraogi return ret; 138fba65fe0SMichael Hennerich } 139fba65fe0SMichael Hennerich 140fba65fe0SMichael Hennerich en_mask = pdata->rows_en_mask | pdata->cols_en_mask; 141fba65fe0SMichael Hennerich 142fba65fe0SMichael Hennerich ret = adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_1, en_mask); 143fba65fe0SMichael Hennerich 144fba65fe0SMichael Hennerich if (en_mask & ADP5520_COL_C3) 145fba65fe0SMichael Hennerich ctl_mask |= ADP5520_C3_MODE; 146fba65fe0SMichael Hennerich 147fba65fe0SMichael Hennerich if (en_mask & ADP5520_ROW_R3) 148fba65fe0SMichael Hennerich ctl_mask |= ADP5520_R3_MODE; 149fba65fe0SMichael Hennerich 150fba65fe0SMichael Hennerich if (ctl_mask) 151fba65fe0SMichael Hennerich ret |= adp5520_set_bits(dev->master, ADP5520_LED_CONTROL, 152fba65fe0SMichael Hennerich ctl_mask); 153fba65fe0SMichael Hennerich 154fba65fe0SMichael Hennerich ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP, 155fba65fe0SMichael Hennerich pdata->rows_en_mask); 156fba65fe0SMichael Hennerich 157fba65fe0SMichael Hennerich if (ret) { 158fba65fe0SMichael Hennerich dev_err(&pdev->dev, "failed to write\n"); 159*ec62c7a8SHimangi Saraogi return -EIO; 160fba65fe0SMichael Hennerich } 161fba65fe0SMichael Hennerich 162fba65fe0SMichael Hennerich dev->notifier.notifier_call = adp5520_keys_notifier; 163fba65fe0SMichael Hennerich ret = adp5520_register_notifier(dev->master, &dev->notifier, 164fba65fe0SMichael Hennerich ADP5520_KP_IEN | ADP5520_KR_IEN); 165fba65fe0SMichael Hennerich if (ret) { 166fba65fe0SMichael Hennerich dev_err(&pdev->dev, "failed to register notifier\n"); 167*ec62c7a8SHimangi Saraogi return ret; 168fba65fe0SMichael Hennerich } 169fba65fe0SMichael Hennerich 170fba65fe0SMichael Hennerich platform_set_drvdata(pdev, dev); 171fba65fe0SMichael Hennerich return 0; 172fba65fe0SMichael Hennerich } 173fba65fe0SMichael Hennerich 174e2619cf7SBill Pemberton static int adp5520_keys_remove(struct platform_device *pdev) 175fba65fe0SMichael Hennerich { 176fba65fe0SMichael Hennerich struct adp5520_keys *dev = platform_get_drvdata(pdev); 177fba65fe0SMichael Hennerich 178fba65fe0SMichael Hennerich adp5520_unregister_notifier(dev->master, &dev->notifier, 179fba65fe0SMichael Hennerich ADP5520_KP_IEN | ADP5520_KR_IEN); 180fba65fe0SMichael Hennerich 181fba65fe0SMichael Hennerich return 0; 182fba65fe0SMichael Hennerich } 183fba65fe0SMichael Hennerich 184fba65fe0SMichael Hennerich static struct platform_driver adp5520_keys_driver = { 185fba65fe0SMichael Hennerich .driver = { 186fba65fe0SMichael Hennerich .name = "adp5520-keys", 187fba65fe0SMichael Hennerich .owner = THIS_MODULE, 188fba65fe0SMichael Hennerich }, 189fba65fe0SMichael Hennerich .probe = adp5520_keys_probe, 1901cb0aa88SBill Pemberton .remove = adp5520_keys_remove, 191fba65fe0SMichael Hennerich }; 1925146c84fSJJ Ding module_platform_driver(adp5520_keys_driver); 193fba65fe0SMichael Hennerich 194fba65fe0SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 195fba65fe0SMichael Hennerich MODULE_DESCRIPTION("Keys ADP5520 Driver"); 196fba65fe0SMichael Hennerich MODULE_LICENSE("GPL"); 197fba65fe0SMichael Hennerich MODULE_ALIAS("platform:adp5520-keys"); 198