Input: add driver for Atmel integrated touchscreen controller

The AT91SAM9RL SoC integrates a Touchscreen Controller which
can trigger ADC conversion periodically.

Signed-off-by: Justin Waters <justin.waters@timesys.com>
Signed-off-by: Dan Liang <dan.liang@atmel.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by Dan Liang and committed by Dmitry Torokhov 72d18a7b 9460b652

+345
+12
drivers/input/touchscreen/Kconfig
··· 205 205 To compile this driver as a module, choose M here: the 206 206 module will be called touchwin. 207 207 208 + config TOUCHSCREEN_ATMEL_TSADCC 209 + tristate "Atmel Touchscreen Interface" 210 + depends on ARCH_AT91SAM9RL 211 + help 212 + Say Y here if you have a 4-wire touchscreen connected to the 213 + ADC Controller on your Atmel SoC (such as the AT91SAM9RL). 214 + 215 + If unsure, say N. 216 + 217 + To compile this driver as a module, choose M here: the 218 + module will be called atmel_tsadcc. 219 + 208 220 config TOUCHSCREEN_UCB1400 209 221 tristate "Philips UCB1400 touchscreen" 210 222 select AC97_BUS
+1
drivers/input/touchscreen/Makefile
··· 7 7 wm97xx-ts-y := wm97xx-core.o 8 8 9 9 obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o 10 + obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o 10 11 obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o 11 12 obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o 12 13 obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
+332
drivers/input/touchscreen/atmel_tsadcc.c
··· 1 + /* 2 + * Atmel Touch Screen Driver 3 + * 4 + * Copyright (c) 2008 ATMEL 5 + * Copyright (c) 2008 Dan Liang 6 + * Copyright (c) 2008 TimeSys Corporation 7 + * Copyright (c) 2008 Justin Waters 8 + * 9 + * Based on touchscreen code from Atmel Corporation. 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License version 2 as 13 + * published by the Free Software Foundation. 14 + */ 15 + #include <linux/init.h> 16 + #include <linux/err.h> 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/input.h> 20 + #include <linux/slab.h> 21 + #include <linux/interrupt.h> 22 + #include <linux/clk.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/io.h> 25 + 26 + /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ 27 + 28 + #define ATMEL_TSADCC_CR 0x00 /* Control register */ 29 + #define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/ 30 + #define ATMEL_TSADCC_START (1 << 1) /* Start conversion */ 31 + 32 + #define ATMEL_TSADCC_MR 0x04 /* Mode register */ 33 + #define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */ 34 + #define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */ 35 + #define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */ 36 + #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ 37 + #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ 38 + #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ 39 + #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ 40 + #define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ 41 + #define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ 42 + #define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ 43 + 44 + #define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */ 45 + #define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */ 46 + #define ATMEL_TSADCC_TRGMOD_NONE (0 << 0) 47 + #define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0) 48 + #define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0) 49 + #define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0) 50 + #define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0) 51 + #define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0) 52 + #define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0) 53 + #define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */ 54 + 55 + #define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */ 56 + #define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */ 57 + #define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */ 58 + 59 + #define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */ 60 + #define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */ 61 + #define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */ 62 + #define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */ 63 + 64 + #define ATMEL_TSADCC_SR 0x1C /* Status register */ 65 + #define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */ 66 + #define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */ 67 + #define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */ 68 + #define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */ 69 + #define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */ 70 + #define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */ 71 + #define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */ 72 + #define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */ 73 + 74 + #define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */ 75 + #define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */ 76 + 77 + #define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */ 78 + #define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */ 79 + #define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */ 80 + #define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */ 81 + #define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */ 82 + #define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */ 83 + #define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */ 84 + #define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ 85 + #define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ 86 + 87 + #define ADC_CLOCK 1000000 88 + 89 + struct atmel_tsadcc { 90 + struct input_dev *input; 91 + char phys[32]; 92 + struct clk *clk; 93 + int irq; 94 + }; 95 + 96 + static void __iomem *tsc_base; 97 + 98 + #define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg)) 99 + #define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg)) 100 + 101 + static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) 102 + { 103 + struct input_dev *input_dev = ((struct atmel_tsadcc *)dev)->input; 104 + 105 + unsigned int absx; 106 + unsigned int absy; 107 + unsigned int status; 108 + unsigned int reg; 109 + 110 + status = atmel_tsadcc_read(ATMEL_TSADCC_SR); 111 + status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR); 112 + 113 + if (status & ATMEL_TSADCC_NOCNT) { 114 + /* Contact lost */ 115 + reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; 116 + 117 + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); 118 + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); 119 + atmel_tsadcc_write(ATMEL_TSADCC_IDR, 120 + ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); 121 + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); 122 + 123 + input_report_key(input_dev, BTN_TOUCH, 0); 124 + input_sync(input_dev); 125 + 126 + } else if (status & ATMEL_TSADCC_PENCNT) { 127 + /* Pen detected */ 128 + reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); 129 + reg &= ~ATMEL_TSADCC_PENDBC; 130 + 131 + atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); 132 + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); 133 + atmel_tsadcc_write(ATMEL_TSADCC_IER, 134 + ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); 135 + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, 136 + ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); 137 + 138 + } else if (status & ATMEL_TSADCC_EOC(3)) { 139 + /* Conversion finished */ 140 + 141 + absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; 142 + absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); 143 + 144 + absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; 145 + absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); 146 + 147 + input_report_abs(input_dev, ABS_X, absx); 148 + input_report_abs(input_dev, ABS_Y, absy); 149 + input_report_key(input_dev, BTN_TOUCH, 1); 150 + input_sync(input_dev); 151 + } 152 + 153 + return IRQ_HANDLED; 154 + } 155 + 156 + /* 157 + * The functions for inserting/removing us as a module. 158 + */ 159 + 160 + static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) 161 + { 162 + struct atmel_tsadcc *ts_dev; 163 + struct input_dev *input_dev; 164 + struct resource *res; 165 + int err = 0; 166 + unsigned int prsc; 167 + unsigned int reg; 168 + 169 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 170 + if (!res) { 171 + dev_err(&pdev->dev, "no mmio resource defined.\n"); 172 + return -ENXIO; 173 + } 174 + 175 + /* Allocate memory for device */ 176 + ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL); 177 + if (!ts_dev) { 178 + dev_err(&pdev->dev, "failed to allocate memory.\n"); 179 + return -ENOMEM; 180 + } 181 + platform_set_drvdata(pdev, ts_dev); 182 + 183 + input_dev = input_allocate_device(); 184 + if (!input_dev) { 185 + dev_err(&pdev->dev, "failed to allocate input device.\n"); 186 + err = -EBUSY; 187 + goto err_free_mem; 188 + } 189 + 190 + ts_dev->irq = platform_get_irq(pdev, 0); 191 + if (ts_dev->irq < 0) { 192 + dev_err(&pdev->dev, "no irq ID is designated.\n"); 193 + err = -ENODEV; 194 + goto err_free_dev; 195 + } 196 + 197 + if (!request_mem_region(res->start, res->end - res->start + 1, 198 + "atmel tsadcc regs")) { 199 + dev_err(&pdev->dev, "resources is unavailable.\n"); 200 + err = -EBUSY; 201 + goto err_free_dev; 202 + } 203 + 204 + tsc_base = ioremap(res->start, res->end - res->start + 1); 205 + if (!tsc_base) { 206 + dev_err(&pdev->dev, "failed to map registers.\n"); 207 + err = -ENOMEM; 208 + goto err_release_mem; 209 + } 210 + 211 + err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED, 212 + pdev->dev.driver->name, ts_dev); 213 + if (err) { 214 + dev_err(&pdev->dev, "failed to allocate irq.\n"); 215 + goto err_unmap_regs; 216 + } 217 + 218 + ts_dev->clk = clk_get(&pdev->dev, "tsc_clk"); 219 + if (IS_ERR(ts_dev->clk)) { 220 + dev_err(&pdev->dev, "failed to get ts_clk\n"); 221 + err = PTR_ERR(ts_dev->clk); 222 + goto err_free_irq; 223 + } 224 + 225 + ts_dev->input = input_dev; 226 + 227 + snprintf(ts_dev->phys, sizeof(ts_dev->phys), 228 + "%s/input0", pdev->dev.bus_id); 229 + 230 + input_dev->name = "atmel touch screen controller"; 231 + input_dev->phys = ts_dev->phys; 232 + input_dev->dev.parent = &pdev->dev; 233 + 234 + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 235 + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 236 + 237 + input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); 238 + input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); 239 + 240 + /* clk_enable() always returns 0, no need to check it */ 241 + clk_enable(ts_dev->clk); 242 + 243 + prsc = clk_get_rate(ts_dev->clk); 244 + dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); 245 + 246 + prsc = prsc / ADC_CLOCK / 2 - 1; 247 + 248 + reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | 249 + ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ 250 + ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ 251 + ((prsc << 8) & ATMEL_TSADCC_PRESCAL) | /* PRESCAL */ 252 + ((0x13 << 16) & ATMEL_TSADCC_STARTUP) | /* STARTUP */ 253 + ((0x0F << 28) & ATMEL_TSADCC_PENDBC); /* PENDBC */ 254 + 255 + atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); 256 + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); 257 + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); 258 + atmel_tsadcc_write(ATMEL_TSADCC_TSR, (0x3 << 24) & ATMEL_TSADCC_TSSHTIM); 259 + 260 + atmel_tsadcc_read(ATMEL_TSADCC_SR); 261 + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); 262 + 263 + /* All went ok, so register to the input system */ 264 + err = input_register_device(input_dev); 265 + if (err) 266 + goto err_fail; 267 + 268 + return 0; 269 + 270 + err_fail: 271 + clk_disable(ts_dev->clk); 272 + clk_put(ts_dev->clk); 273 + err_free_irq: 274 + free_irq(ts_dev->irq, ts_dev); 275 + err_unmap_regs: 276 + iounmap(tsc_base); 277 + err_release_mem: 278 + release_mem_region(res->start, res->end - res->start + 1); 279 + err_free_dev: 280 + input_free_device(ts_dev->input); 281 + err_free_mem: 282 + kfree(ts_dev); 283 + return err; 284 + } 285 + 286 + static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) 287 + { 288 + struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); 289 + struct resource *res; 290 + 291 + free_irq(ts_dev->irq, ts_dev); 292 + 293 + input_unregister_device(ts_dev->input); 294 + 295 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 296 + iounmap(tsc_base); 297 + release_mem_region(res->start, res->end - res->start + 1); 298 + 299 + clk_disable(ts_dev->clk); 300 + clk_put(ts_dev->clk); 301 + 302 + kfree(ts_dev); 303 + 304 + return 0; 305 + } 306 + 307 + static struct platform_driver atmel_tsadcc_driver = { 308 + .probe = atmel_tsadcc_probe, 309 + .remove = __devexit_p(atmel_tsadcc_remove), 310 + .driver = { 311 + .name = "atmel_tsadcc", 312 + }, 313 + }; 314 + 315 + static int __init atmel_tsadcc_init(void) 316 + { 317 + return platform_driver_register(&atmel_tsadcc_driver); 318 + } 319 + 320 + static void __exit atmel_tsadcc_exit(void) 321 + { 322 + platform_driver_unregister(&atmel_tsadcc_driver); 323 + } 324 + 325 + module_init(atmel_tsadcc_init); 326 + module_exit(atmel_tsadcc_exit); 327 + 328 + 329 + MODULE_LICENSE("GPL"); 330 + MODULE_DESCRIPTION("Atmel TouchScreen Driver"); 331 + MODULE_AUTHOR("Dan Liang <dan.liang@atmel.com>"); 332 +