pxa930_rotary.c (4376B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Driver for the enhanced rotary controller on pxa930 and pxa935 4 */ 5 6#include <linux/kernel.h> 7#include <linux/module.h> 8#include <linux/interrupt.h> 9#include <linux/input.h> 10#include <linux/platform_device.h> 11#include <linux/io.h> 12#include <linux/slab.h> 13 14#include <linux/platform_data/keyboard-pxa930_rotary.h> 15 16#define SBCR (0x04) 17#define ERCR (0x0c) 18 19#define SBCR_ERSB (1 << 5) 20 21struct pxa930_rotary { 22 struct input_dev *input_dev; 23 void __iomem *mmio_base; 24 int last_ercr; 25 26 struct pxa930_rotary_platform_data *pdata; 27}; 28 29static void clear_sbcr(struct pxa930_rotary *r) 30{ 31 uint32_t sbcr = __raw_readl(r->mmio_base + SBCR); 32 33 __raw_writel(sbcr | SBCR_ERSB, r->mmio_base + SBCR); 34 __raw_writel(sbcr & ~SBCR_ERSB, r->mmio_base + SBCR); 35} 36 37static irqreturn_t rotary_irq(int irq, void *dev_id) 38{ 39 struct pxa930_rotary *r = dev_id; 40 struct pxa930_rotary_platform_data *pdata = r->pdata; 41 int ercr, delta, key; 42 43 ercr = __raw_readl(r->mmio_base + ERCR) & 0xf; 44 clear_sbcr(r); 45 46 delta = ercr - r->last_ercr; 47 if (delta == 0) 48 return IRQ_HANDLED; 49 50 r->last_ercr = ercr; 51 52 if (pdata->up_key && pdata->down_key) { 53 key = (delta > 0) ? pdata->up_key : pdata->down_key; 54 input_report_key(r->input_dev, key, 1); 55 input_sync(r->input_dev); 56 input_report_key(r->input_dev, key, 0); 57 } else 58 input_report_rel(r->input_dev, pdata->rel_code, delta); 59 60 input_sync(r->input_dev); 61 62 return IRQ_HANDLED; 63} 64 65static int pxa930_rotary_open(struct input_dev *dev) 66{ 67 struct pxa930_rotary *r = input_get_drvdata(dev); 68 69 clear_sbcr(r); 70 71 return 0; 72} 73 74static void pxa930_rotary_close(struct input_dev *dev) 75{ 76 struct pxa930_rotary *r = input_get_drvdata(dev); 77 78 clear_sbcr(r); 79} 80 81static int pxa930_rotary_probe(struct platform_device *pdev) 82{ 83 struct pxa930_rotary_platform_data *pdata = 84 dev_get_platdata(&pdev->dev); 85 struct pxa930_rotary *r; 86 struct input_dev *input_dev; 87 struct resource *res; 88 int irq; 89 int err; 90 91 irq = platform_get_irq(pdev, 0); 92 if (irq < 0) 93 return -ENXIO; 94 95 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 96 if (!res) { 97 dev_err(&pdev->dev, "no I/O memory defined\n"); 98 return -ENXIO; 99 } 100 101 if (!pdata) { 102 dev_err(&pdev->dev, "no platform data defined\n"); 103 return -EINVAL; 104 } 105 106 r = kzalloc(sizeof(struct pxa930_rotary), GFP_KERNEL); 107 if (!r) 108 return -ENOMEM; 109 110 r->mmio_base = ioremap(res->start, resource_size(res)); 111 if (r->mmio_base == NULL) { 112 dev_err(&pdev->dev, "failed to remap IO memory\n"); 113 err = -ENXIO; 114 goto failed_free; 115 } 116 117 r->pdata = pdata; 118 platform_set_drvdata(pdev, r); 119 120 /* allocate and register the input device */ 121 input_dev = input_allocate_device(); 122 if (!input_dev) { 123 dev_err(&pdev->dev, "failed to allocate input device\n"); 124 err = -ENOMEM; 125 goto failed_free_io; 126 } 127 128 input_dev->name = pdev->name; 129 input_dev->id.bustype = BUS_HOST; 130 input_dev->open = pxa930_rotary_open; 131 input_dev->close = pxa930_rotary_close; 132 input_dev->dev.parent = &pdev->dev; 133 134 if (pdata->up_key && pdata->down_key) { 135 __set_bit(pdata->up_key, input_dev->keybit); 136 __set_bit(pdata->down_key, input_dev->keybit); 137 __set_bit(EV_KEY, input_dev->evbit); 138 } else { 139 __set_bit(pdata->rel_code, input_dev->relbit); 140 __set_bit(EV_REL, input_dev->evbit); 141 } 142 143 r->input_dev = input_dev; 144 input_set_drvdata(input_dev, r); 145 146 err = request_irq(irq, rotary_irq, 0, 147 "enhanced rotary", r); 148 if (err) { 149 dev_err(&pdev->dev, "failed to request IRQ\n"); 150 goto failed_free_input; 151 } 152 153 err = input_register_device(input_dev); 154 if (err) { 155 dev_err(&pdev->dev, "failed to register input device\n"); 156 goto failed_free_irq; 157 } 158 159 return 0; 160 161failed_free_irq: 162 free_irq(irq, r); 163failed_free_input: 164 input_free_device(input_dev); 165failed_free_io: 166 iounmap(r->mmio_base); 167failed_free: 168 kfree(r); 169 return err; 170} 171 172static int pxa930_rotary_remove(struct platform_device *pdev) 173{ 174 struct pxa930_rotary *r = platform_get_drvdata(pdev); 175 176 free_irq(platform_get_irq(pdev, 0), r); 177 input_unregister_device(r->input_dev); 178 iounmap(r->mmio_base); 179 kfree(r); 180 181 return 0; 182} 183 184static struct platform_driver pxa930_rotary_driver = { 185 .driver = { 186 .name = "pxa930-rotary", 187 }, 188 .probe = pxa930_rotary_probe, 189 .remove = pxa930_rotary_remove, 190}; 191module_platform_driver(pxa930_rotary_driver); 192 193MODULE_LICENSE("GPL"); 194MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller"); 195MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");