Path: blob/master/drivers/input/touchscreen/atmel_tsadcc.c
15111 views
/*1* Atmel Touch Screen Driver2*3* Copyright (c) 2008 ATMEL4* Copyright (c) 2008 Dan Liang5* Copyright (c) 2008 TimeSys Corporation6* Copyright (c) 2008 Justin Waters7*8* Based on touchscreen code from Atmel Corporation.9*10* This program is free software; you can redistribute it and/or modify11* it under the terms of the GNU General Public License version 2 as12* published by the Free Software Foundation.13*/14#include <linux/init.h>15#include <linux/err.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/input.h>19#include <linux/slab.h>20#include <linux/interrupt.h>21#include <linux/clk.h>22#include <linux/platform_device.h>23#include <linux/io.h>24#include <mach/board.h>25#include <mach/cpu.h>2627/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */2829#define ATMEL_TSADCC_CR 0x00 /* Control register */30#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/31#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */3233#define ATMEL_TSADCC_MR 0x04 /* Mode register */34#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */35#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */36#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */37#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */38#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */39#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */40#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */41#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */42#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */43#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */44#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */45#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */4647#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */48#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */49#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)50#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)51#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)52#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)53#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)54#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)55#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)56#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */5758#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */59#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */60#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */6162#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */63#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */64#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */65#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */6667#define ATMEL_TSADCC_SR 0x1C /* Status register */68#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */69#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */70#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */71#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */72#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */73#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */74#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */75#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */7677#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */78#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */7980#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */81#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */82#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */83#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */84#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */85#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */86#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */87#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */88#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */8990#define ATMEL_TSADCC_XPOS 0x5091#define ATMEL_TSADCC_Z1DAT 0x5492#define ATMEL_TSADCC_Z2DAT 0x589394#define PRESCALER_VAL(x) ((x) >> 8)9596#define ADC_DEFAULT_CLOCK 1000009798struct atmel_tsadcc {99struct input_dev *input;100char phys[32];101struct clk *clk;102int irq;103unsigned int prev_absx;104unsigned int prev_absy;105unsigned char bufferedmeasure;106};107108static void __iomem *tsc_base;109110#define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg))111#define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg))112113static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)114{115struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;116struct input_dev *input_dev = ts_dev->input;117118unsigned int status;119unsigned int reg;120121status = atmel_tsadcc_read(ATMEL_TSADCC_SR);122status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR);123124if (status & ATMEL_TSADCC_NOCNT) {125/* Contact lost */126reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;127128atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);129atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);130atmel_tsadcc_write(ATMEL_TSADCC_IDR,131ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);132atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);133134input_report_key(input_dev, BTN_TOUCH, 0);135ts_dev->bufferedmeasure = 0;136input_sync(input_dev);137138} else if (status & ATMEL_TSADCC_PENCNT) {139/* Pen detected */140reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);141reg &= ~ATMEL_TSADCC_PENDBC;142143atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);144atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);145atmel_tsadcc_write(ATMEL_TSADCC_IER,146ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);147atmel_tsadcc_write(ATMEL_TSADCC_TRGR,148ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));149150} else if (status & ATMEL_TSADCC_EOC(3)) {151/* Conversion finished */152153if (ts_dev->bufferedmeasure) {154/* Last measurement is always discarded, since it can155* be erroneous.156* Always report previous measurement */157input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);158input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);159input_report_key(input_dev, BTN_TOUCH, 1);160input_sync(input_dev);161} else162ts_dev->bufferedmeasure = 1;163164/* Now make new measurement */165ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;166ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);167168ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;169ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);170}171172return IRQ_HANDLED;173}174175/*176* The functions for inserting/removing us as a module.177*/178179static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)180{181struct atmel_tsadcc *ts_dev;182struct input_dev *input_dev;183struct resource *res;184struct at91_tsadcc_data *pdata = pdev->dev.platform_data;185int err = 0;186unsigned int prsc;187unsigned int reg;188189res = platform_get_resource(pdev, IORESOURCE_MEM, 0);190if (!res) {191dev_err(&pdev->dev, "no mmio resource defined.\n");192return -ENXIO;193}194195/* Allocate memory for device */196ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL);197if (!ts_dev) {198dev_err(&pdev->dev, "failed to allocate memory.\n");199return -ENOMEM;200}201platform_set_drvdata(pdev, ts_dev);202203input_dev = input_allocate_device();204if (!input_dev) {205dev_err(&pdev->dev, "failed to allocate input device.\n");206err = -EBUSY;207goto err_free_mem;208}209210ts_dev->irq = platform_get_irq(pdev, 0);211if (ts_dev->irq < 0) {212dev_err(&pdev->dev, "no irq ID is designated.\n");213err = -ENODEV;214goto err_free_dev;215}216217if (!request_mem_region(res->start, resource_size(res),218"atmel tsadcc regs")) {219dev_err(&pdev->dev, "resources is unavailable.\n");220err = -EBUSY;221goto err_free_dev;222}223224tsc_base = ioremap(res->start, resource_size(res));225if (!tsc_base) {226dev_err(&pdev->dev, "failed to map registers.\n");227err = -ENOMEM;228goto err_release_mem;229}230231err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED,232pdev->dev.driver->name, ts_dev);233if (err) {234dev_err(&pdev->dev, "failed to allocate irq.\n");235goto err_unmap_regs;236}237238ts_dev->clk = clk_get(&pdev->dev, "tsc_clk");239if (IS_ERR(ts_dev->clk)) {240dev_err(&pdev->dev, "failed to get ts_clk\n");241err = PTR_ERR(ts_dev->clk);242goto err_free_irq;243}244245ts_dev->input = input_dev;246ts_dev->bufferedmeasure = 0;247248snprintf(ts_dev->phys, sizeof(ts_dev->phys),249"%s/input0", dev_name(&pdev->dev));250251input_dev->name = "atmel touch screen controller";252input_dev->phys = ts_dev->phys;253input_dev->dev.parent = &pdev->dev;254255__set_bit(EV_ABS, input_dev->evbit);256input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);257input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);258259input_set_capability(input_dev, EV_KEY, BTN_TOUCH);260261/* clk_enable() always returns 0, no need to check it */262clk_enable(ts_dev->clk);263264prsc = clk_get_rate(ts_dev->clk);265dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);266267if (!pdata)268goto err_fail;269270if (!pdata->adc_clock)271pdata->adc_clock = ADC_DEFAULT_CLOCK;272273prsc = (prsc / (2 * pdata->adc_clock)) - 1;274275/* saturate if this value is too high */276if (cpu_is_at91sam9rl()) {277if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL))278prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL);279} else {280if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL))281prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL);282}283284dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);285286reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |287((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */288((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */289(prsc << 8) |290((0x26 << 16) & ATMEL_TSADCC_STARTUP) |291((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);292293atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);294atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);295atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);296atmel_tsadcc_write(ATMEL_TSADCC_TSR,297(pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);298299atmel_tsadcc_read(ATMEL_TSADCC_SR);300atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);301302/* All went ok, so register to the input system */303err = input_register_device(input_dev);304if (err)305goto err_fail;306307return 0;308309err_fail:310clk_disable(ts_dev->clk);311clk_put(ts_dev->clk);312err_free_irq:313free_irq(ts_dev->irq, ts_dev);314err_unmap_regs:315iounmap(tsc_base);316err_release_mem:317release_mem_region(res->start, resource_size(res));318err_free_dev:319input_free_device(input_dev);320err_free_mem:321kfree(ts_dev);322return err;323}324325static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)326{327struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev);328struct resource *res;329330free_irq(ts_dev->irq, ts_dev);331332input_unregister_device(ts_dev->input);333334res = platform_get_resource(pdev, IORESOURCE_MEM, 0);335iounmap(tsc_base);336release_mem_region(res->start, resource_size(res));337338clk_disable(ts_dev->clk);339clk_put(ts_dev->clk);340341kfree(ts_dev);342343return 0;344}345346static struct platform_driver atmel_tsadcc_driver = {347.probe = atmel_tsadcc_probe,348.remove = __devexit_p(atmel_tsadcc_remove),349.driver = {350.name = "atmel_tsadcc",351},352};353354static int __init atmel_tsadcc_init(void)355{356return platform_driver_register(&atmel_tsadcc_driver);357}358359static void __exit atmel_tsadcc_exit(void)360{361platform_driver_unregister(&atmel_tsadcc_driver);362}363364module_init(atmel_tsadcc_init);365module_exit(atmel_tsadcc_exit);366367368MODULE_LICENSE("GPL");369MODULE_DESCRIPTION("Atmel TouchScreen Driver");370MODULE_AUTHOR("Dan Liang <[email protected]>");371372373374