1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2d81ca730SKsenija Stanojevic /* 3d81ca730SKsenija Stanojevic * Freescale MXS LRADC touchscreen driver 4d81ca730SKsenija Stanojevic * 5d81ca730SKsenija Stanojevic * Copyright (c) 2012 DENX Software Engineering, GmbH. 6d81ca730SKsenija Stanojevic * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com> 7d81ca730SKsenija Stanojevic * 8d81ca730SKsenija Stanojevic * Authors: 9d81ca730SKsenija Stanojevic * Marek Vasut <marex@denx.de> 10d81ca730SKsenija Stanojevic * Ksenija Stanojevic <ksenija.stanojevic@gmail.com> 11d81ca730SKsenija Stanojevic */ 12d81ca730SKsenija Stanojevic 13d81ca730SKsenija Stanojevic #include <linux/device.h> 14d81ca730SKsenija Stanojevic #include <linux/err.h> 15d81ca730SKsenija Stanojevic #include <linux/input.h> 16d81ca730SKsenija Stanojevic #include <linux/interrupt.h> 17d81ca730SKsenija Stanojevic #include <linux/module.h> 18d81ca730SKsenija Stanojevic #include <linux/mfd/core.h> 19d81ca730SKsenija Stanojevic #include <linux/mfd/mxs-lradc.h> 20d81ca730SKsenija Stanojevic #include <linux/of.h> 21d81ca730SKsenija Stanojevic #include <linux/of_irq.h> 22d81ca730SKsenija Stanojevic #include <linux/platform_device.h> 23d81ca730SKsenija Stanojevic 242e53d52cSWei Yongjun static const char * const mxs_lradc_ts_irq_names[] = { 25d81ca730SKsenija Stanojevic "mxs-lradc-touchscreen", 26d81ca730SKsenija Stanojevic "mxs-lradc-channel6", 27d81ca730SKsenija Stanojevic "mxs-lradc-channel7", 28d81ca730SKsenija Stanojevic }; 29d81ca730SKsenija Stanojevic 30d81ca730SKsenija Stanojevic /* 31d81ca730SKsenija Stanojevic * Touchscreen handling 32d81ca730SKsenija Stanojevic */ 33d81ca730SKsenija Stanojevic enum mxs_lradc_ts_plate { 34d81ca730SKsenija Stanojevic LRADC_TOUCH = 0, 35d81ca730SKsenija Stanojevic LRADC_SAMPLE_X, 36d81ca730SKsenija Stanojevic LRADC_SAMPLE_Y, 37d81ca730SKsenija Stanojevic LRADC_SAMPLE_PRESSURE, 38d81ca730SKsenija Stanojevic LRADC_SAMPLE_VALID, 39d81ca730SKsenija Stanojevic }; 40d81ca730SKsenija Stanojevic 41d81ca730SKsenija Stanojevic struct mxs_lradc_ts { 42d81ca730SKsenija Stanojevic struct mxs_lradc *lradc; 43d81ca730SKsenija Stanojevic struct device *dev; 44d81ca730SKsenija Stanojevic 45d81ca730SKsenija Stanojevic void __iomem *base; 46d81ca730SKsenija Stanojevic /* 47d81ca730SKsenija Stanojevic * When the touchscreen is enabled, we give it two private virtual 48d81ca730SKsenija Stanojevic * channels: #6 and #7. This means that only 6 virtual channels (instead 49d81ca730SKsenija Stanojevic * of 8) will be available for buffered capture. 50d81ca730SKsenija Stanojevic */ 51d81ca730SKsenija Stanojevic #define TOUCHSCREEN_VCHANNEL1 7 52d81ca730SKsenija Stanojevic #define TOUCHSCREEN_VCHANNEL2 6 53d81ca730SKsenija Stanojevic 54d81ca730SKsenija Stanojevic struct input_dev *ts_input; 55d81ca730SKsenija Stanojevic 56d81ca730SKsenija Stanojevic enum mxs_lradc_ts_plate cur_plate; /* state machine */ 57d81ca730SKsenija Stanojevic bool ts_valid; 58d81ca730SKsenija Stanojevic unsigned int ts_x_pos; 59d81ca730SKsenija Stanojevic unsigned int ts_y_pos; 60d81ca730SKsenija Stanojevic unsigned int ts_pressure; 61d81ca730SKsenija Stanojevic 62d81ca730SKsenija Stanojevic /* handle touchscreen's physical behaviour */ 63d81ca730SKsenija Stanojevic /* samples per coordinate */ 64d81ca730SKsenija Stanojevic unsigned int over_sample_cnt; 65d81ca730SKsenija Stanojevic /* time clocks between samples */ 66d81ca730SKsenija Stanojevic unsigned int over_sample_delay; 67d81ca730SKsenija Stanojevic /* time in clocks to wait after the plates where switched */ 68d81ca730SKsenija Stanojevic unsigned int settling_delay; 69d81ca730SKsenija Stanojevic spinlock_t lock; 70d81ca730SKsenija Stanojevic }; 71d81ca730SKsenija Stanojevic 72d81ca730SKsenija Stanojevic struct state_info { 73d81ca730SKsenija Stanojevic u32 mask; 74d81ca730SKsenija Stanojevic u32 bit; 75d81ca730SKsenija Stanojevic u32 x_plate; 76d81ca730SKsenija Stanojevic u32 y_plate; 77d81ca730SKsenija Stanojevic u32 pressure; 78d81ca730SKsenija Stanojevic }; 79d81ca730SKsenija Stanojevic 80d81ca730SKsenija Stanojevic static struct state_info info[] = { 81d81ca730SKsenija Stanojevic {LRADC_CTRL0_MX23_PLATE_MASK, LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE, 82d81ca730SKsenija Stanojevic LRADC_CTRL0_MX23_XP | LRADC_CTRL0_MX23_XM, 83d81ca730SKsenija Stanojevic LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_YM, 84d81ca730SKsenija Stanojevic LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XM}, 85d81ca730SKsenija Stanojevic {LRADC_CTRL0_MX28_PLATE_MASK, LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE, 86d81ca730SKsenija Stanojevic LRADC_CTRL0_MX28_XPPSW | LRADC_CTRL0_MX28_XNNSW, 87d81ca730SKsenija Stanojevic LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_YNNSW, 88d81ca730SKsenija Stanojevic LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW} 89d81ca730SKsenija Stanojevic }; 90d81ca730SKsenija Stanojevic 91d81ca730SKsenija Stanojevic static bool mxs_lradc_check_touch_event(struct mxs_lradc_ts *ts) 92d81ca730SKsenija Stanojevic { 93d81ca730SKsenija Stanojevic return !!(readl(ts->base + LRADC_STATUS) & 94d81ca730SKsenija Stanojevic LRADC_STATUS_TOUCH_DETECT_RAW); 95d81ca730SKsenija Stanojevic } 96d81ca730SKsenija Stanojevic 97d81ca730SKsenija Stanojevic static void mxs_lradc_map_ts_channel(struct mxs_lradc_ts *ts, unsigned int vch, 98d81ca730SKsenija Stanojevic unsigned int ch) 99d81ca730SKsenija Stanojevic { 100d81ca730SKsenija Stanojevic writel(LRADC_CTRL4_LRADCSELECT_MASK(vch), 101d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); 102d81ca730SKsenija Stanojevic writel(LRADC_CTRL4_LRADCSELECT(vch, ch), 103d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); 104d81ca730SKsenija Stanojevic } 105d81ca730SKsenija Stanojevic 106d81ca730SKsenija Stanojevic static void mxs_lradc_setup_ts_channel(struct mxs_lradc_ts *ts, unsigned int ch) 107d81ca730SKsenija Stanojevic { 108d81ca730SKsenija Stanojevic /* 109d81ca730SKsenija Stanojevic * prepare for oversampling conversion 110d81ca730SKsenija Stanojevic * 111d81ca730SKsenija Stanojevic * from the datasheet: 112d81ca730SKsenija Stanojevic * "The ACCUMULATE bit in the appropriate channel register 113d81ca730SKsenija Stanojevic * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; 114d81ca730SKsenija Stanojevic * otherwise, the IRQs will not fire." 115d81ca730SKsenija Stanojevic */ 116d81ca730SKsenija Stanojevic writel(LRADC_CH_ACCUMULATE | 117d81ca730SKsenija Stanojevic LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1), 118d81ca730SKsenija Stanojevic ts->base + LRADC_CH(ch)); 119d81ca730SKsenija Stanojevic 120d81ca730SKsenija Stanojevic /* from the datasheet: 121d81ca730SKsenija Stanojevic * "Software must clear this register in preparation for a 122d81ca730SKsenija Stanojevic * multi-cycle accumulation. 123d81ca730SKsenija Stanojevic */ 124d81ca730SKsenija Stanojevic writel(LRADC_CH_VALUE_MASK, 125d81ca730SKsenija Stanojevic ts->base + LRADC_CH(ch) + STMP_OFFSET_REG_CLR); 126d81ca730SKsenija Stanojevic 127d81ca730SKsenija Stanojevic /* 128d81ca730SKsenija Stanojevic * prepare the delay/loop unit according to the oversampling count 129d81ca730SKsenija Stanojevic * 130d81ca730SKsenija Stanojevic * from the datasheet: 131d81ca730SKsenija Stanojevic * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1, 132d81ca730SKsenija Stanojevic * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise, 133d81ca730SKsenija Stanojevic * the LRADC will not trigger the delay group." 134d81ca730SKsenija Stanojevic */ 135d81ca730SKsenija Stanojevic writel(LRADC_DELAY_TRIGGER(1 << ch) | LRADC_DELAY_TRIGGER_DELAYS(0) | 136d81ca730SKsenija Stanojevic LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) | 137d81ca730SKsenija Stanojevic LRADC_DELAY_DELAY(ts->over_sample_delay - 1), 138d81ca730SKsenija Stanojevic ts->base + LRADC_DELAY(3)); 139d81ca730SKsenija Stanojevic 140d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_LRADC_IRQ(ch), 141d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 142d81ca730SKsenija Stanojevic 143d81ca730SKsenija Stanojevic /* 144d81ca730SKsenija Stanojevic * after changing the touchscreen plates setting 145d81ca730SKsenija Stanojevic * the signals need some initial time to settle. Start the 146d81ca730SKsenija Stanojevic * SoC's delay unit and start the conversion later 147d81ca730SKsenija Stanojevic * and automatically. 148d81ca730SKsenija Stanojevic */ 149d81ca730SKsenija Stanojevic writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) | 150d81ca730SKsenija Stanojevic LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay), 151d81ca730SKsenija Stanojevic ts->base + LRADC_DELAY(2)); 152d81ca730SKsenija Stanojevic } 153d81ca730SKsenija Stanojevic 154d81ca730SKsenija Stanojevic /* 155d81ca730SKsenija Stanojevic * Pressure detection is special: 156d81ca730SKsenija Stanojevic * We want to do both required measurements for the pressure detection in 157d81ca730SKsenija Stanojevic * one turn. Use the hardware features to chain both conversions and let the 158d81ca730SKsenija Stanojevic * hardware report one interrupt if both conversions are done 159d81ca730SKsenija Stanojevic */ 160d81ca730SKsenija Stanojevic static void mxs_lradc_setup_ts_pressure(struct mxs_lradc_ts *ts, 161d81ca730SKsenija Stanojevic unsigned int ch1, unsigned int ch2) 162d81ca730SKsenija Stanojevic { 163d81ca730SKsenija Stanojevic u32 reg; 164d81ca730SKsenija Stanojevic 165d81ca730SKsenija Stanojevic /* 166d81ca730SKsenija Stanojevic * prepare for oversampling conversion 167d81ca730SKsenija Stanojevic * 168d81ca730SKsenija Stanojevic * from the datasheet: 169d81ca730SKsenija Stanojevic * "The ACCUMULATE bit in the appropriate channel register 170d81ca730SKsenija Stanojevic * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; 171d81ca730SKsenija Stanojevic * otherwise, the IRQs will not fire." 172d81ca730SKsenija Stanojevic */ 173d81ca730SKsenija Stanojevic reg = LRADC_CH_ACCUMULATE | 174d81ca730SKsenija Stanojevic LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1); 175d81ca730SKsenija Stanojevic writel(reg, ts->base + LRADC_CH(ch1)); 176d81ca730SKsenija Stanojevic writel(reg, ts->base + LRADC_CH(ch2)); 177d81ca730SKsenija Stanojevic 178d81ca730SKsenija Stanojevic /* from the datasheet: 179d81ca730SKsenija Stanojevic * "Software must clear this register in preparation for a 180d81ca730SKsenija Stanojevic * multi-cycle accumulation. 181d81ca730SKsenija Stanojevic */ 182d81ca730SKsenija Stanojevic writel(LRADC_CH_VALUE_MASK, 183d81ca730SKsenija Stanojevic ts->base + LRADC_CH(ch1) + STMP_OFFSET_REG_CLR); 184d81ca730SKsenija Stanojevic writel(LRADC_CH_VALUE_MASK, 185d81ca730SKsenija Stanojevic ts->base + LRADC_CH(ch2) + STMP_OFFSET_REG_CLR); 186d81ca730SKsenija Stanojevic 187d81ca730SKsenija Stanojevic /* prepare the delay/loop unit according to the oversampling count */ 188d81ca730SKsenija Stanojevic writel(LRADC_DELAY_TRIGGER(1 << ch1) | LRADC_DELAY_TRIGGER(1 << ch2) | 189d81ca730SKsenija Stanojevic LRADC_DELAY_TRIGGER_DELAYS(0) | 190d81ca730SKsenija Stanojevic LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) | 191d81ca730SKsenija Stanojevic LRADC_DELAY_DELAY(ts->over_sample_delay - 1), 192d81ca730SKsenija Stanojevic ts->base + LRADC_DELAY(3)); 193d81ca730SKsenija Stanojevic 194d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_LRADC_IRQ(ch2), 195d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 196d81ca730SKsenija Stanojevic 197d81ca730SKsenija Stanojevic /* 198d81ca730SKsenija Stanojevic * after changing the touchscreen plates setting 199d81ca730SKsenija Stanojevic * the signals need some initial time to settle. Start the 200d81ca730SKsenija Stanojevic * SoC's delay unit and start the conversion later 201d81ca730SKsenija Stanojevic * and automatically. 202d81ca730SKsenija Stanojevic */ 203d81ca730SKsenija Stanojevic writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) | 204d81ca730SKsenija Stanojevic LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay), 205d81ca730SKsenija Stanojevic ts->base + LRADC_DELAY(2)); 206d81ca730SKsenija Stanojevic } 207d81ca730SKsenija Stanojevic 208d81ca730SKsenija Stanojevic static unsigned int mxs_lradc_ts_read_raw_channel(struct mxs_lradc_ts *ts, 209d81ca730SKsenija Stanojevic unsigned int channel) 210d81ca730SKsenija Stanojevic { 211d81ca730SKsenija Stanojevic u32 reg; 212d81ca730SKsenija Stanojevic unsigned int num_samples, val; 213d81ca730SKsenija Stanojevic 214d81ca730SKsenija Stanojevic reg = readl(ts->base + LRADC_CH(channel)); 215d81ca730SKsenija Stanojevic if (reg & LRADC_CH_ACCUMULATE) 216d81ca730SKsenija Stanojevic num_samples = ts->over_sample_cnt; 217d81ca730SKsenija Stanojevic else 218d81ca730SKsenija Stanojevic num_samples = 1; 219d81ca730SKsenija Stanojevic 220d81ca730SKsenija Stanojevic val = (reg & LRADC_CH_VALUE_MASK) >> LRADC_CH_VALUE_OFFSET; 221d81ca730SKsenija Stanojevic return val / num_samples; 222d81ca730SKsenija Stanojevic } 223d81ca730SKsenija Stanojevic 224d81ca730SKsenija Stanojevic static unsigned int mxs_lradc_read_ts_pressure(struct mxs_lradc_ts *ts, 225d81ca730SKsenija Stanojevic unsigned int ch1, unsigned int ch2) 226d81ca730SKsenija Stanojevic { 227d81ca730SKsenija Stanojevic u32 reg, mask; 228d81ca730SKsenija Stanojevic unsigned int pressure, m1, m2; 229d81ca730SKsenija Stanojevic 230d81ca730SKsenija Stanojevic mask = LRADC_CTRL1_LRADC_IRQ(ch1) | LRADC_CTRL1_LRADC_IRQ(ch2); 231d81ca730SKsenija Stanojevic reg = readl(ts->base + LRADC_CTRL1) & mask; 232d81ca730SKsenija Stanojevic 233d81ca730SKsenija Stanojevic while (reg != mask) { 234d81ca730SKsenija Stanojevic reg = readl(ts->base + LRADC_CTRL1) & mask; 235d81ca730SKsenija Stanojevic dev_dbg(ts->dev, "One channel is still busy: %X\n", reg); 236d81ca730SKsenija Stanojevic } 237d81ca730SKsenija Stanojevic 238d81ca730SKsenija Stanojevic m1 = mxs_lradc_ts_read_raw_channel(ts, ch1); 239d81ca730SKsenija Stanojevic m2 = mxs_lradc_ts_read_raw_channel(ts, ch2); 240d81ca730SKsenija Stanojevic 241d81ca730SKsenija Stanojevic if (m2 == 0) { 242d81ca730SKsenija Stanojevic dev_warn(ts->dev, "Cannot calculate pressure\n"); 243d81ca730SKsenija Stanojevic return 1 << (LRADC_RESOLUTION - 1); 244d81ca730SKsenija Stanojevic } 245d81ca730SKsenija Stanojevic 246d81ca730SKsenija Stanojevic /* simply scale the value from 0 ... max ADC resolution */ 247d81ca730SKsenija Stanojevic pressure = m1; 248d81ca730SKsenija Stanojevic pressure *= (1 << LRADC_RESOLUTION); 249d81ca730SKsenija Stanojevic pressure /= m2; 250d81ca730SKsenija Stanojevic 251d81ca730SKsenija Stanojevic dev_dbg(ts->dev, "Pressure = %u\n", pressure); 252d81ca730SKsenija Stanojevic return pressure; 253d81ca730SKsenija Stanojevic } 254d81ca730SKsenija Stanojevic 255d81ca730SKsenija Stanojevic #define TS_CH_XP 2 256d81ca730SKsenija Stanojevic #define TS_CH_YP 3 257d81ca730SKsenija Stanojevic #define TS_CH_XM 4 258d81ca730SKsenija Stanojevic #define TS_CH_YM 5 259d81ca730SKsenija Stanojevic 260d81ca730SKsenija Stanojevic /* 261d81ca730SKsenija Stanojevic * YP(open)--+-------------+ 262d81ca730SKsenija Stanojevic * | |--+ 263d81ca730SKsenija Stanojevic * | | | 264d81ca730SKsenija Stanojevic * YM(-)--+-------------+ | 265d81ca730SKsenija Stanojevic * +--------------+ 266d81ca730SKsenija Stanojevic * | | 267d81ca730SKsenija Stanojevic * XP(weak+) XM(open) 268d81ca730SKsenija Stanojevic * 269d81ca730SKsenija Stanojevic * "weak+" means 200k Ohm VDDIO 270d81ca730SKsenija Stanojevic * (-) means GND 271d81ca730SKsenija Stanojevic */ 272d81ca730SKsenija Stanojevic static void mxs_lradc_setup_touch_detection(struct mxs_lradc_ts *ts) 273d81ca730SKsenija Stanojevic { 274d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 275d81ca730SKsenija Stanojevic 276d81ca730SKsenija Stanojevic /* 277d81ca730SKsenija Stanojevic * In order to detect a touch event the 'touch detect enable' bit 278d81ca730SKsenija Stanojevic * enables: 279d81ca730SKsenija Stanojevic * - a weak pullup to the X+ connector 280d81ca730SKsenija Stanojevic * - a strong ground at the Y- connector 281d81ca730SKsenija Stanojevic */ 282d81ca730SKsenija Stanojevic writel(info[lradc->soc].mask, 283d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); 284d81ca730SKsenija Stanojevic writel(info[lradc->soc].bit, 285d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); 286d81ca730SKsenija Stanojevic } 287d81ca730SKsenija Stanojevic 288d81ca730SKsenija Stanojevic /* 289d81ca730SKsenija Stanojevic * YP(meas)--+-------------+ 290d81ca730SKsenija Stanojevic * | |--+ 291d81ca730SKsenija Stanojevic * | | | 292d81ca730SKsenija Stanojevic * YM(open)--+-------------+ | 293d81ca730SKsenija Stanojevic * +--------------+ 294d81ca730SKsenija Stanojevic * | | 295d81ca730SKsenija Stanojevic * XP(+) XM(-) 296d81ca730SKsenija Stanojevic * 297d81ca730SKsenija Stanojevic * (+) means here 1.85 V 298d81ca730SKsenija Stanojevic * (-) means here GND 299d81ca730SKsenija Stanojevic */ 300d81ca730SKsenija Stanojevic static void mxs_lradc_prepare_x_pos(struct mxs_lradc_ts *ts) 301d81ca730SKsenija Stanojevic { 302d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 303d81ca730SKsenija Stanojevic 304d81ca730SKsenija Stanojevic writel(info[lradc->soc].mask, 305d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); 306d81ca730SKsenija Stanojevic writel(info[lradc->soc].x_plate, 307d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); 308d81ca730SKsenija Stanojevic 309d81ca730SKsenija Stanojevic ts->cur_plate = LRADC_SAMPLE_X; 310d81ca730SKsenija Stanojevic mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_YP); 311d81ca730SKsenija Stanojevic mxs_lradc_setup_ts_channel(ts, TOUCHSCREEN_VCHANNEL1); 312d81ca730SKsenija Stanojevic } 313d81ca730SKsenija Stanojevic 314d81ca730SKsenija Stanojevic /* 315d81ca730SKsenija Stanojevic * YP(+)--+-------------+ 316d81ca730SKsenija Stanojevic * | |--+ 317d81ca730SKsenija Stanojevic * | | | 318d81ca730SKsenija Stanojevic * YM(-)--+-------------+ | 319d81ca730SKsenija Stanojevic * +--------------+ 320d81ca730SKsenija Stanojevic * | | 321d81ca730SKsenija Stanojevic * XP(open) XM(meas) 322d81ca730SKsenija Stanojevic * 323d81ca730SKsenija Stanojevic * (+) means here 1.85 V 324d81ca730SKsenija Stanojevic * (-) means here GND 325d81ca730SKsenija Stanojevic */ 326d81ca730SKsenija Stanojevic static void mxs_lradc_prepare_y_pos(struct mxs_lradc_ts *ts) 327d81ca730SKsenija Stanojevic { 328d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 329d81ca730SKsenija Stanojevic 330d81ca730SKsenija Stanojevic writel(info[lradc->soc].mask, 331d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); 332d81ca730SKsenija Stanojevic writel(info[lradc->soc].y_plate, 333d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); 334d81ca730SKsenija Stanojevic 335d81ca730SKsenija Stanojevic ts->cur_plate = LRADC_SAMPLE_Y; 336d81ca730SKsenija Stanojevic mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_XM); 337d81ca730SKsenija Stanojevic mxs_lradc_setup_ts_channel(ts, TOUCHSCREEN_VCHANNEL1); 338d81ca730SKsenija Stanojevic } 339d81ca730SKsenija Stanojevic 340d81ca730SKsenija Stanojevic /* 341d81ca730SKsenija Stanojevic * YP(+)--+-------------+ 342d81ca730SKsenija Stanojevic * | |--+ 343d81ca730SKsenija Stanojevic * | | | 344d81ca730SKsenija Stanojevic * YM(meas)--+-------------+ | 345d81ca730SKsenija Stanojevic * +--------------+ 346d81ca730SKsenija Stanojevic * | | 347d81ca730SKsenija Stanojevic * XP(meas) XM(-) 348d81ca730SKsenija Stanojevic * 349d81ca730SKsenija Stanojevic * (+) means here 1.85 V 350d81ca730SKsenija Stanojevic * (-) means here GND 351d81ca730SKsenija Stanojevic */ 352d81ca730SKsenija Stanojevic static void mxs_lradc_prepare_pressure(struct mxs_lradc_ts *ts) 353d81ca730SKsenija Stanojevic { 354d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 355d81ca730SKsenija Stanojevic 356d81ca730SKsenija Stanojevic writel(info[lradc->soc].mask, 357d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); 358d81ca730SKsenija Stanojevic writel(info[lradc->soc].pressure, 359d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); 360d81ca730SKsenija Stanojevic 361d81ca730SKsenija Stanojevic ts->cur_plate = LRADC_SAMPLE_PRESSURE; 362d81ca730SKsenija Stanojevic mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_YM); 363d81ca730SKsenija Stanojevic mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL2, TS_CH_XP); 364d81ca730SKsenija Stanojevic mxs_lradc_setup_ts_pressure(ts, TOUCHSCREEN_VCHANNEL2, 365d81ca730SKsenija Stanojevic TOUCHSCREEN_VCHANNEL1); 366d81ca730SKsenija Stanojevic } 367d81ca730SKsenija Stanojevic 368d81ca730SKsenija Stanojevic static void mxs_lradc_enable_touch_detection(struct mxs_lradc_ts *ts) 369d81ca730SKsenija Stanojevic { 370d81ca730SKsenija Stanojevic mxs_lradc_setup_touch_detection(ts); 371d81ca730SKsenija Stanojevic 372d81ca730SKsenija Stanojevic ts->cur_plate = LRADC_TOUCH; 373d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ | LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, 374d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 375d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, 376d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); 377d81ca730SKsenija Stanojevic } 378d81ca730SKsenija Stanojevic 379d81ca730SKsenija Stanojevic static void mxs_lradc_start_touch_event(struct mxs_lradc_ts *ts) 380d81ca730SKsenija Stanojevic { 381d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, 382d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 383d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), 384d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); 385d81ca730SKsenija Stanojevic /* 386d81ca730SKsenija Stanojevic * start with the Y-pos, because it uses nearly the same plate 387d81ca730SKsenija Stanojevic * settings like the touch detection 388d81ca730SKsenija Stanojevic */ 389d81ca730SKsenija Stanojevic mxs_lradc_prepare_y_pos(ts); 390d81ca730SKsenija Stanojevic } 391d81ca730SKsenija Stanojevic 392d81ca730SKsenija Stanojevic static void mxs_lradc_report_ts_event(struct mxs_lradc_ts *ts) 393d81ca730SKsenija Stanojevic { 394d81ca730SKsenija Stanojevic input_report_abs(ts->ts_input, ABS_X, ts->ts_x_pos); 395d81ca730SKsenija Stanojevic input_report_abs(ts->ts_input, ABS_Y, ts->ts_y_pos); 396d81ca730SKsenija Stanojevic input_report_abs(ts->ts_input, ABS_PRESSURE, ts->ts_pressure); 397d81ca730SKsenija Stanojevic input_report_key(ts->ts_input, BTN_TOUCH, 1); 398d81ca730SKsenija Stanojevic input_sync(ts->ts_input); 399d81ca730SKsenija Stanojevic } 400d81ca730SKsenija Stanojevic 401d81ca730SKsenija Stanojevic static void mxs_lradc_complete_touch_event(struct mxs_lradc_ts *ts) 402d81ca730SKsenija Stanojevic { 403d81ca730SKsenija Stanojevic mxs_lradc_setup_touch_detection(ts); 404d81ca730SKsenija Stanojevic ts->cur_plate = LRADC_SAMPLE_VALID; 405d81ca730SKsenija Stanojevic /* 406d81ca730SKsenija Stanojevic * start a dummy conversion to burn time to settle the signals 407d81ca730SKsenija Stanojevic * note: we are not interested in the conversion's value 408d81ca730SKsenija Stanojevic */ 409d81ca730SKsenija Stanojevic writel(0, ts->base + LRADC_CH(TOUCHSCREEN_VCHANNEL1)); 410d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | 411d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), 412d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 413d81ca730SKsenija Stanojevic writel(LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) | 414d81ca730SKsenija Stanojevic LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), 415d81ca730SKsenija Stanojevic ts->base + LRADC_DELAY(2)); 416d81ca730SKsenija Stanojevic } 417d81ca730SKsenija Stanojevic 418d81ca730SKsenija Stanojevic /* 419d81ca730SKsenija Stanojevic * in order to avoid false measurements, report only samples where 420d81ca730SKsenija Stanojevic * the surface is still touched after the position measurement 421d81ca730SKsenija Stanojevic */ 422d81ca730SKsenija Stanojevic static void mxs_lradc_finish_touch_event(struct mxs_lradc_ts *ts, bool valid) 423d81ca730SKsenija Stanojevic { 424d81ca730SKsenija Stanojevic /* if it is still touched, report the sample */ 425d81ca730SKsenija Stanojevic if (valid && mxs_lradc_check_touch_event(ts)) { 426d81ca730SKsenija Stanojevic ts->ts_valid = true; 427d81ca730SKsenija Stanojevic mxs_lradc_report_ts_event(ts); 428d81ca730SKsenija Stanojevic } 429d81ca730SKsenija Stanojevic 430d81ca730SKsenija Stanojevic /* if it is even still touched, continue with the next measurement */ 431d81ca730SKsenija Stanojevic if (mxs_lradc_check_touch_event(ts)) { 432d81ca730SKsenija Stanojevic mxs_lradc_prepare_y_pos(ts); 433d81ca730SKsenija Stanojevic return; 434d81ca730SKsenija Stanojevic } 435d81ca730SKsenija Stanojevic 436d81ca730SKsenija Stanojevic if (ts->ts_valid) { 437d81ca730SKsenija Stanojevic /* signal the release */ 438d81ca730SKsenija Stanojevic ts->ts_valid = false; 439d81ca730SKsenija Stanojevic input_report_key(ts->ts_input, BTN_TOUCH, 0); 440d81ca730SKsenija Stanojevic input_sync(ts->ts_input); 441d81ca730SKsenija Stanojevic } 442d81ca730SKsenija Stanojevic 443d81ca730SKsenija Stanojevic /* if it is released, wait for the next touch via IRQ */ 444d81ca730SKsenija Stanojevic ts->cur_plate = LRADC_TOUCH; 445d81ca730SKsenija Stanojevic writel(0, ts->base + LRADC_DELAY(2)); 446d81ca730SKsenija Stanojevic writel(0, ts->base + LRADC_DELAY(3)); 447d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ | 448d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) | 449d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), 450d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 451d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, 452d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); 453d81ca730SKsenija Stanojevic } 454d81ca730SKsenija Stanojevic 455d81ca730SKsenija Stanojevic /* touchscreen's state machine */ 456d81ca730SKsenija Stanojevic static void mxs_lradc_handle_touch(struct mxs_lradc_ts *ts) 457d81ca730SKsenija Stanojevic { 458d81ca730SKsenija Stanojevic switch (ts->cur_plate) { 459d81ca730SKsenija Stanojevic case LRADC_TOUCH: 460d81ca730SKsenija Stanojevic if (mxs_lradc_check_touch_event(ts)) 461d81ca730SKsenija Stanojevic mxs_lradc_start_touch_event(ts); 462d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ, 463d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 464d81ca730SKsenija Stanojevic return; 465d81ca730SKsenija Stanojevic 466d81ca730SKsenija Stanojevic case LRADC_SAMPLE_Y: 467d81ca730SKsenija Stanojevic ts->ts_y_pos = 468d81ca730SKsenija Stanojevic mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1); 469d81ca730SKsenija Stanojevic mxs_lradc_prepare_x_pos(ts); 470d81ca730SKsenija Stanojevic return; 471d81ca730SKsenija Stanojevic 472d81ca730SKsenija Stanojevic case LRADC_SAMPLE_X: 473d81ca730SKsenija Stanojevic ts->ts_x_pos = 474d81ca730SKsenija Stanojevic mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1); 475d81ca730SKsenija Stanojevic mxs_lradc_prepare_pressure(ts); 476d81ca730SKsenija Stanojevic return; 477d81ca730SKsenija Stanojevic 478d81ca730SKsenija Stanojevic case LRADC_SAMPLE_PRESSURE: 479d81ca730SKsenija Stanojevic ts->ts_pressure = 480d81ca730SKsenija Stanojevic mxs_lradc_read_ts_pressure(ts, 481d81ca730SKsenija Stanojevic TOUCHSCREEN_VCHANNEL2, 482d81ca730SKsenija Stanojevic TOUCHSCREEN_VCHANNEL1); 483d81ca730SKsenija Stanojevic mxs_lradc_complete_touch_event(ts); 484d81ca730SKsenija Stanojevic return; 485d81ca730SKsenija Stanojevic 486d81ca730SKsenija Stanojevic case LRADC_SAMPLE_VALID: 487d81ca730SKsenija Stanojevic mxs_lradc_finish_touch_event(ts, 1); 488d81ca730SKsenija Stanojevic break; 489d81ca730SKsenija Stanojevic } 490d81ca730SKsenija Stanojevic } 491d81ca730SKsenija Stanojevic 492d81ca730SKsenija Stanojevic /* IRQ Handling */ 493d81ca730SKsenija Stanojevic static irqreturn_t mxs_lradc_ts_handle_irq(int irq, void *data) 494d81ca730SKsenija Stanojevic { 495d81ca730SKsenija Stanojevic struct mxs_lradc_ts *ts = data; 496d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 497d81ca730SKsenija Stanojevic unsigned long reg = readl(ts->base + LRADC_CTRL1); 498d81ca730SKsenija Stanojevic u32 clr_irq = mxs_lradc_irq_mask(lradc); 499d81ca730SKsenija Stanojevic const u32 ts_irq_mask = 500d81ca730SKsenija Stanojevic LRADC_CTRL1_TOUCH_DETECT_IRQ | 501d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | 502d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2); 503d81ca730SKsenija Stanojevic unsigned long flags; 504d81ca730SKsenija Stanojevic 505d81ca730SKsenija Stanojevic if (!(reg & mxs_lradc_irq_mask(lradc))) 506d81ca730SKsenija Stanojevic return IRQ_NONE; 507d81ca730SKsenija Stanojevic 508d81ca730SKsenija Stanojevic if (reg & ts_irq_mask) { 509d81ca730SKsenija Stanojevic spin_lock_irqsave(&ts->lock, flags); 510d81ca730SKsenija Stanojevic mxs_lradc_handle_touch(ts); 511d81ca730SKsenija Stanojevic spin_unlock_irqrestore(&ts->lock, flags); 512d81ca730SKsenija Stanojevic /* Make sure we don't clear the next conversion's interrupt. */ 513d81ca730SKsenija Stanojevic clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | 514d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2)); 515d81ca730SKsenija Stanojevic writel(reg & clr_irq, 516d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 517d81ca730SKsenija Stanojevic } 518d81ca730SKsenija Stanojevic 519d81ca730SKsenija Stanojevic return IRQ_HANDLED; 520d81ca730SKsenija Stanojevic } 521d81ca730SKsenija Stanojevic 522d81ca730SKsenija Stanojevic static int mxs_lradc_ts_open(struct input_dev *dev) 523d81ca730SKsenija Stanojevic { 524d81ca730SKsenija Stanojevic struct mxs_lradc_ts *ts = input_get_drvdata(dev); 525d81ca730SKsenija Stanojevic 526d81ca730SKsenija Stanojevic /* Enable the touch-detect circuitry. */ 527d81ca730SKsenija Stanojevic mxs_lradc_enable_touch_detection(ts); 528d81ca730SKsenija Stanojevic 529d81ca730SKsenija Stanojevic return 0; 530d81ca730SKsenija Stanojevic } 531d81ca730SKsenija Stanojevic 532d81ca730SKsenija Stanojevic static void mxs_lradc_ts_stop(struct mxs_lradc_ts *ts) 533d81ca730SKsenija Stanojevic { 534d81ca730SKsenija Stanojevic int i; 535d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 536d81ca730SKsenija Stanojevic 537d81ca730SKsenija Stanojevic /* stop all interrupts from firing */ 538d81ca730SKsenija Stanojevic writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | 539d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) | 540d81ca730SKsenija Stanojevic LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), 541d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 542d81ca730SKsenija Stanojevic 543d81ca730SKsenija Stanojevic /* Power-down touchscreen touch-detect circuitry. */ 544d81ca730SKsenija Stanojevic writel(info[lradc->soc].mask, 545d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); 546d81ca730SKsenija Stanojevic 547d81ca730SKsenija Stanojevic writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET, 548d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); 549d81ca730SKsenija Stanojevic 550d81ca730SKsenija Stanojevic for (i = 1; i < LRADC_MAX_DELAY_CHANS; i++) 551d81ca730SKsenija Stanojevic writel(0, ts->base + LRADC_DELAY(i)); 552d81ca730SKsenija Stanojevic } 553d81ca730SKsenija Stanojevic 554d81ca730SKsenija Stanojevic static void mxs_lradc_ts_close(struct input_dev *dev) 555d81ca730SKsenija Stanojevic { 556d81ca730SKsenija Stanojevic struct mxs_lradc_ts *ts = input_get_drvdata(dev); 557d81ca730SKsenija Stanojevic 558d81ca730SKsenija Stanojevic mxs_lradc_ts_stop(ts); 559d81ca730SKsenija Stanojevic } 560d81ca730SKsenija Stanojevic 561d81ca730SKsenija Stanojevic static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts) 562d81ca730SKsenija Stanojevic { 563d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = ts->lradc; 564d81ca730SKsenija Stanojevic 565d81ca730SKsenija Stanojevic /* Configure the touchscreen type */ 566d81ca730SKsenija Stanojevic if (lradc->soc == IMX28_LRADC) { 567d81ca730SKsenija Stanojevic writel(LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE, 568d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); 569d81ca730SKsenija Stanojevic 570d81ca730SKsenija Stanojevic if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_5WIRE) 571d81ca730SKsenija Stanojevic writel(LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE, 572d81ca730SKsenija Stanojevic ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); 573d81ca730SKsenija Stanojevic } 574d81ca730SKsenija Stanojevic } 575d81ca730SKsenija Stanojevic 576d81ca730SKsenija Stanojevic static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts) 577d81ca730SKsenija Stanojevic { 57811772c9cSColin Ian King struct input_dev *input; 579d81ca730SKsenija Stanojevic struct device *dev = ts->dev; 580d81ca730SKsenija Stanojevic 581d81ca730SKsenija Stanojevic input = devm_input_allocate_device(dev); 582d81ca730SKsenija Stanojevic if (!input) 583d81ca730SKsenija Stanojevic return -ENOMEM; 584d81ca730SKsenija Stanojevic 585d81ca730SKsenija Stanojevic input->name = "mxs-lradc-ts"; 586d81ca730SKsenija Stanojevic input->id.bustype = BUS_HOST; 587d81ca730SKsenija Stanojevic input->open = mxs_lradc_ts_open; 588d81ca730SKsenija Stanojevic input->close = mxs_lradc_ts_close; 589d81ca730SKsenija Stanojevic 590d81ca730SKsenija Stanojevic __set_bit(INPUT_PROP_DIRECT, input->propbit); 591d81ca730SKsenija Stanojevic input_set_capability(input, EV_KEY, BTN_TOUCH); 592d81ca730SKsenija Stanojevic input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0); 593d81ca730SKsenija Stanojevic input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0); 594d81ca730SKsenija Stanojevic input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK, 595d81ca730SKsenija Stanojevic 0, 0); 596d81ca730SKsenija Stanojevic 597d81ca730SKsenija Stanojevic ts->ts_input = input; 598d81ca730SKsenija Stanojevic input_set_drvdata(input, ts); 599d81ca730SKsenija Stanojevic 600d81ca730SKsenija Stanojevic return input_register_device(input); 601d81ca730SKsenija Stanojevic } 602d81ca730SKsenija Stanojevic 603d81ca730SKsenija Stanojevic static int mxs_lradc_ts_probe(struct platform_device *pdev) 604d81ca730SKsenija Stanojevic { 605d81ca730SKsenija Stanojevic struct device *dev = &pdev->dev; 606d81ca730SKsenija Stanojevic struct device_node *node = dev->parent->of_node; 607d81ca730SKsenija Stanojevic struct mxs_lradc *lradc = dev_get_drvdata(dev->parent); 608d81ca730SKsenija Stanojevic struct mxs_lradc_ts *ts; 609d81ca730SKsenija Stanojevic int ret, irq, virq, i; 610d81ca730SKsenija Stanojevic u32 ts_wires = 0, adapt; 611d81ca730SKsenija Stanojevic 612d81ca730SKsenija Stanojevic ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); 613d81ca730SKsenija Stanojevic if (!ts) 614d81ca730SKsenija Stanojevic return -ENOMEM; 615d81ca730SKsenija Stanojevic 616d81ca730SKsenija Stanojevic platform_set_drvdata(pdev, ts); 617d81ca730SKsenija Stanojevic 618d81ca730SKsenija Stanojevic ts->lradc = lradc; 619d81ca730SKsenija Stanojevic ts->dev = dev; 620d81ca730SKsenija Stanojevic spin_lock_init(&ts->lock); 621d81ca730SKsenija Stanojevic 622*46bec7a9SMukesh Ojha ts->base = devm_platform_ioremap_resource(pdev, 0); 623*46bec7a9SMukesh Ojha if (IS_ERR(ts->base)) 624*46bec7a9SMukesh Ojha return PTR_ERR(ts->base); 625d81ca730SKsenija Stanojevic 626d81ca730SKsenija Stanojevic ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires", 627d81ca730SKsenija Stanojevic &ts_wires); 628d81ca730SKsenija Stanojevic if (ret) 629d81ca730SKsenija Stanojevic return ret; 630d81ca730SKsenija Stanojevic 631d81ca730SKsenija Stanojevic if (of_property_read_u32(node, "fsl,ave-ctrl", &adapt)) { 632d81ca730SKsenija Stanojevic ts->over_sample_cnt = 4; 633d81ca730SKsenija Stanojevic } else { 634ab6241aeSDan Carpenter if (adapt >= 1 && adapt <= 32) { 635d81ca730SKsenija Stanojevic ts->over_sample_cnt = adapt; 636d81ca730SKsenija Stanojevic } else { 637d81ca730SKsenija Stanojevic dev_err(ts->dev, "Invalid sample count (%u)\n", 638d81ca730SKsenija Stanojevic adapt); 639d81ca730SKsenija Stanojevic return -EINVAL; 640d81ca730SKsenija Stanojevic } 641d81ca730SKsenija Stanojevic } 642d81ca730SKsenija Stanojevic 643d81ca730SKsenija Stanojevic if (of_property_read_u32(node, "fsl,ave-delay", &adapt)) { 644d81ca730SKsenija Stanojevic ts->over_sample_delay = 2; 645d81ca730SKsenija Stanojevic } else { 646ab6241aeSDan Carpenter if (adapt >= 2 && adapt <= LRADC_DELAY_DELAY_MASK + 1) { 647d81ca730SKsenija Stanojevic ts->over_sample_delay = adapt; 648d81ca730SKsenija Stanojevic } else { 649d81ca730SKsenija Stanojevic dev_err(ts->dev, "Invalid sample delay (%u)\n", 650d81ca730SKsenija Stanojevic adapt); 651d81ca730SKsenija Stanojevic return -EINVAL; 652d81ca730SKsenija Stanojevic } 653d81ca730SKsenija Stanojevic } 654d81ca730SKsenija Stanojevic 655d81ca730SKsenija Stanojevic if (of_property_read_u32(node, "fsl,settling", &adapt)) { 656d81ca730SKsenija Stanojevic ts->settling_delay = 10; 657d81ca730SKsenija Stanojevic } else { 658ab6241aeSDan Carpenter if (adapt >= 1 && adapt <= LRADC_DELAY_DELAY_MASK) { 659d81ca730SKsenija Stanojevic ts->settling_delay = adapt; 660d81ca730SKsenija Stanojevic } else { 661d81ca730SKsenija Stanojevic dev_err(ts->dev, "Invalid settling delay (%u)\n", 662d81ca730SKsenija Stanojevic adapt); 663d81ca730SKsenija Stanojevic return -EINVAL; 664d81ca730SKsenija Stanojevic } 665d81ca730SKsenija Stanojevic } 666d81ca730SKsenija Stanojevic 667d81ca730SKsenija Stanojevic ret = stmp_reset_block(ts->base); 668d81ca730SKsenija Stanojevic if (ret) 669d81ca730SKsenija Stanojevic return ret; 670d81ca730SKsenija Stanojevic 671d81ca730SKsenija Stanojevic mxs_lradc_ts_hw_init(ts); 672d81ca730SKsenija Stanojevic 673d81ca730SKsenija Stanojevic for (i = 0; i < 3; i++) { 674d81ca730SKsenija Stanojevic irq = platform_get_irq_byname(pdev, mxs_lradc_ts_irq_names[i]); 675d81ca730SKsenija Stanojevic if (irq < 0) 676d81ca730SKsenija Stanojevic return irq; 677d81ca730SKsenija Stanojevic 678d81ca730SKsenija Stanojevic virq = irq_of_parse_and_map(node, irq); 679d81ca730SKsenija Stanojevic 680d81ca730SKsenija Stanojevic mxs_lradc_ts_stop(ts); 681d81ca730SKsenija Stanojevic 682d81ca730SKsenija Stanojevic ret = devm_request_irq(dev, virq, 683d81ca730SKsenija Stanojevic mxs_lradc_ts_handle_irq, 684d81ca730SKsenija Stanojevic 0, mxs_lradc_ts_irq_names[i], ts); 685d81ca730SKsenija Stanojevic if (ret) 686d81ca730SKsenija Stanojevic return ret; 687d81ca730SKsenija Stanojevic } 688d81ca730SKsenija Stanojevic 689d81ca730SKsenija Stanojevic return mxs_lradc_ts_register(ts); 690d81ca730SKsenija Stanojevic } 691d81ca730SKsenija Stanojevic 692d81ca730SKsenija Stanojevic static struct platform_driver mxs_lradc_ts_driver = { 693d81ca730SKsenija Stanojevic .driver = { 694d81ca730SKsenija Stanojevic .name = "mxs-lradc-ts", 695d81ca730SKsenija Stanojevic }, 696d81ca730SKsenija Stanojevic .probe = mxs_lradc_ts_probe, 697d81ca730SKsenija Stanojevic }; 698d81ca730SKsenija Stanojevic module_platform_driver(mxs_lradc_ts_driver); 699d81ca730SKsenija Stanojevic 700d81ca730SKsenija Stanojevic MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 701d81ca730SKsenija Stanojevic MODULE_DESCRIPTION("Freescale MXS LRADC touchscreen driver"); 702d81ca730SKsenija Stanojevic MODULE_LICENSE("GPL"); 703d81ca730SKsenija Stanojevic MODULE_ALIAS("platform:mxs-lradc-ts"); 704