File Index
Files and directories
Sign in
FILE

fsl-imx25-tcq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/input/touchscreen/fsl-imx25-tcq.c C
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
  4// Based on driver from 2011:
  5//   Juergen Beisert, Pengutronix <kernel@pengutronix.de>
  6//
  7// This is the driver for the imx25 TCQ (Touchscreen Conversion Queue)
  8// connected to the imx25 ADC.
  9
 10#include <linux/clk.h>
 11#include <linux/device.h>
 12#include <linux/input.h>
 13#include <linux/interrupt.h>
 14#include <linux/mfd/imx25-tsadc.h>
 15#include <linux/module.h>
 16#include <linux/of.h>
 17#include <linux/platform_device.h>
 18#include <linux/regmap.h>
 19
 20static const char mx25_tcq_name[] = "mx25-tcq";
 21
 22enum mx25_tcq_mode {
 23	MX25_TS_4WIRE,
 24};
 25
 26struct mx25_tcq_priv {
 27	struct regmap *regs;
 28	struct regmap *core_regs;
 29	struct input_dev *idev;
 30	enum mx25_tcq_mode mode;
 31	unsigned int pen_threshold;
 32	unsigned int sample_count;
 33	unsigned int expected_samples;
 34	unsigned int pen_debounce;
 35	unsigned int settling_time;
 36	struct clk *clk;
 37	int irq;
 38	struct device *dev;
 39};
 40
 41static const struct regmap_config mx25_tcq_regconfig = {
 42	.max_register = 0x5c,
 43	.reg_bits = 32,
 44	.val_bits = 32,
 45	.reg_stride = 4,
 46};
 47
 48static const struct of_device_id mx25_tcq_ids[] = {
 49	{ .compatible = "fsl,imx25-tcq", },
 50	{ /* Sentinel */ }
 51};
 52MODULE_DEVICE_TABLE(of, mx25_tcq_ids);
 53
 54#define TSC_4WIRE_PRE_INDEX 0
 55#define TSC_4WIRE_X_INDEX 1
 56#define TSC_4WIRE_Y_INDEX 2
 57#define TSC_4WIRE_POST_INDEX 3
 58#define TSC_4WIRE_LEAVE 4
 59
 60#define MX25_TSC_DEF_THRESHOLD 80
 61#define TSC_MAX_SAMPLES 16
 62
 63#define MX25_TSC_REPEAT_WAIT 14
 64
 65enum mx25_adc_configurations {
 66	MX25_CFG_PRECHARGE = 0,
 67	MX25_CFG_TOUCH_DETECT,
 68	MX25_CFG_X_MEASUREMENT,
 69	MX25_CFG_Y_MEASUREMENT,
 70};
 71
 72#define MX25_PRECHARGE_VALUE (\
 73			MX25_ADCQ_CFG_YPLL_OFF | \
 74			MX25_ADCQ_CFG_XNUR_OFF | \
 75			MX25_ADCQ_CFG_XPUL_HIGH | \
 76			MX25_ADCQ_CFG_REFP_INT | \
 77			MX25_ADCQ_CFG_IN_XP | \
 78			MX25_ADCQ_CFG_REFN_NGND2 | \
 79			MX25_ADCQ_CFG_IGS)
 80
 81#define MX25_TOUCH_DETECT_VALUE (\
 82			MX25_ADCQ_CFG_YNLR | \
 83			MX25_ADCQ_CFG_YPLL_OFF | \
 84			MX25_ADCQ_CFG_XNUR_OFF | \
 85			MX25_ADCQ_CFG_XPUL_OFF | \
 86			MX25_ADCQ_CFG_REFP_INT | \
 87			MX25_ADCQ_CFG_IN_XP | \
 88			MX25_ADCQ_CFG_REFN_NGND2 | \
 89			MX25_ADCQ_CFG_PENIACK)
 90
 91static void imx25_setup_queue_cfgs(struct mx25_tcq_priv *priv,
 92				   unsigned int settling_cnt)
 93{
 94	u32 precharge_cfg =
 95			MX25_PRECHARGE_VALUE |
 96			MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt);
 97	u32 touch_detect_cfg =
 98			MX25_TOUCH_DETECT_VALUE |
 99			MX25_ADCQ_CFG_NOS(1) |
100			MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt);
101
102	regmap_write(priv->core_regs, MX25_TSC_TICR, precharge_cfg);
103
104	/* PRECHARGE */
105	regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_PRECHARGE),
106		     precharge_cfg);
107
108	/* TOUCH_DETECT */
109	regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_TOUCH_DETECT),
110		     touch_detect_cfg);
111
112	/* X Measurement */
113	regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_X_MEASUREMENT),
114		     MX25_ADCQ_CFG_YPLL_OFF |
115		     MX25_ADCQ_CFG_XNUR_LOW |
116		     MX25_ADCQ_CFG_XPUL_HIGH |
117		     MX25_ADCQ_CFG_REFP_XP |
118		     MX25_ADCQ_CFG_IN_YP |
119		     MX25_ADCQ_CFG_REFN_XN |
120		     MX25_ADCQ_CFG_NOS(priv->sample_count) |
121		     MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt));
122
123	/* Y Measurement */
124	regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_Y_MEASUREMENT),
125		     MX25_ADCQ_CFG_YNLR |
126		     MX25_ADCQ_CFG_YPLL_HIGH |
127		     MX25_ADCQ_CFG_XNUR_OFF |
128		     MX25_ADCQ_CFG_XPUL_OFF |
129		     MX25_ADCQ_CFG_REFP_YP |
130		     MX25_ADCQ_CFG_IN_XP |
131		     MX25_ADCQ_CFG_REFN_YN |
132		     MX25_ADCQ_CFG_NOS(priv->sample_count) |
133		     MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt));
134
135	/* Enable the touch detection right now */
136	regmap_write(priv->core_regs, MX25_TSC_TICR, touch_detect_cfg |
137		     MX25_ADCQ_CFG_IGS);
138}
139
140static int imx25_setup_queue_4wire(struct mx25_tcq_priv *priv,
141				   unsigned settling_cnt, int *items)
142{
143	imx25_setup_queue_cfgs(priv, settling_cnt);
144
145	/* Setup the conversion queue */
146	regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
147		     MX25_ADCQ_ITEM(0, MX25_CFG_PRECHARGE) |
148		     MX25_ADCQ_ITEM(1, MX25_CFG_TOUCH_DETECT) |
149		     MX25_ADCQ_ITEM(2, MX25_CFG_X_MEASUREMENT) |
150		     MX25_ADCQ_ITEM(3, MX25_CFG_Y_MEASUREMENT) |
151		     MX25_ADCQ_ITEM(4, MX25_CFG_PRECHARGE) |
152		     MX25_ADCQ_ITEM(5, MX25_CFG_TOUCH_DETECT));
153
154	/*
155	 * We measure X/Y with 'sample_count' number of samples and execute a
156	 * touch detection twice, with 1 sample each
157	 */
158	priv->expected_samples = priv->sample_count * 2 + 2;
159	*items = 6;
160
161	return 0;
162}
163
164static void mx25_tcq_disable_touch_irq(struct mx25_tcq_priv *priv)
165{
166	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK,
167			   MX25_ADCQ_CR_PDMSK);
168}
169
170static void mx25_tcq_enable_touch_irq(struct mx25_tcq_priv *priv)
171{
172	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK, 0);
173}
174
175static void mx25_tcq_disable_fifo_irq(struct mx25_tcq_priv *priv)
176{
177	regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ,
178			   MX25_ADCQ_MR_FDRY_IRQ);
179}
180
181static void mx25_tcq_enable_fifo_irq(struct mx25_tcq_priv *priv)
182{
183	regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ, 0);
184}
185
186static void mx25_tcq_force_queue_start(struct mx25_tcq_priv *priv)
187{
188	regmap_update_bits(priv->regs, MX25_ADCQ_CR,
189			   MX25_ADCQ_CR_FQS,
190			   MX25_ADCQ_CR_FQS);
191}
192
193static void mx25_tcq_force_queue_stop(struct mx25_tcq_priv *priv)
194{
195	regmap_update_bits(priv->regs, MX25_ADCQ_CR,
196			   MX25_ADCQ_CR_FQS, 0);
197}
198
199static void mx25_tcq_fifo_reset(struct mx25_tcq_priv *priv)
200{
201	u32 tcqcr;
202
203	regmap_read(priv->regs, MX25_ADCQ_CR, &tcqcr);
204	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST,
205			   MX25_ADCQ_CR_FRST);
206	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST, 0);
207	regmap_write(priv->regs, MX25_ADCQ_CR, tcqcr);
208}
209
210static void mx25_tcq_re_enable_touch_detection(struct mx25_tcq_priv *priv)
211{
212	/* stop the queue from looping */
213	mx25_tcq_force_queue_stop(priv);
214
215	/* for a clean touch detection, preload the X plane */
216	regmap_write(priv->core_regs, MX25_TSC_TICR, MX25_PRECHARGE_VALUE);
217
218	/* waste some time now to pre-load the X plate to high voltage */
219	mx25_tcq_fifo_reset(priv);
220
221	/* re-enable the detection right now */
222	regmap_write(priv->core_regs, MX25_TSC_TICR,
223		     MX25_TOUCH_DETECT_VALUE | MX25_ADCQ_CFG_IGS);
224
225	regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_PD,
226			   MX25_ADCQ_SR_PD);
227
228	/* enable the pen down event to be a source for the interrupt */
229	regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_PD_IRQ, 0);
230
231	/* lets fire the next IRQ if someone touches the touchscreen */
232	mx25_tcq_enable_touch_irq(priv);
233}
234
235static void mx25_tcq_create_event_for_4wire(struct mx25_tcq_priv *priv,
236					    u32 *sample_buf,
237					    unsigned int samples)
238{
239	unsigned int x_pos = 0;
240	unsigned int y_pos = 0;
241	unsigned int touch_pre = 0;
242	unsigned int touch_post = 0;
243	unsigned int i;
244
245	for (i = 0; i < samples; i++) {
246		unsigned int index = MX25_ADCQ_FIFO_ID(sample_buf[i]);
247		unsigned int val = MX25_ADCQ_FIFO_DATA(sample_buf[i]);
248
249		switch (index) {
250		case 1:
251			touch_pre = val;
252			break;
253		case 2:
254			x_pos = val;
255			break;
256		case 3:
257			y_pos = val;
258			break;
259		case 5:
260			touch_post = val;
261			break;
262		default:
263			dev_dbg(priv->dev, "Dropped samples because of invalid index %d\n",
264				index);
265			return;
266		}
267	}
268
269	if (samples != 0) {
270		/*
271		 * only if both touch measures are below a threshold,
272		 * the position is valid
273		 */
274		if (touch_pre < priv->pen_threshold &&
275		    touch_post < priv->pen_threshold) {
276			/* valid samples, generate a report */
277			x_pos /= priv->sample_count;
278			y_pos /= priv->sample_count;
279			input_report_abs(priv->idev, ABS_X, x_pos);
280			input_report_abs(priv->idev, ABS_Y, y_pos);
281			input_report_key(priv->idev, BTN_TOUCH, 1);
282			input_sync(priv->idev);
283
284			/* get next sample */
285			mx25_tcq_enable_fifo_irq(priv);
286		} else if (touch_pre >= priv->pen_threshold &&
287			   touch_post >= priv->pen_threshold) {
288			/*
289			 * if both samples are invalid,
290			 * generate a release report
291			 */
292			input_report_key(priv->idev, BTN_TOUCH, 0);
293			input_sync(priv->idev);
294			mx25_tcq_re_enable_touch_detection(priv);
295		} else {
296			/*
297			 * if only one of both touch measurements are
298			 * below the threshold, still some bouncing
299			 * happens. Take additional samples in this
300			 * case to be sure
301			 */
302			mx25_tcq_enable_fifo_irq(priv);
303		}
304	}
305}
306
307static irqreturn_t mx25_tcq_irq_thread(int irq, void *dev_id)
308{
309	struct mx25_tcq_priv *priv = dev_id;
310	u32 sample_buf[TSC_MAX_SAMPLES];
311	unsigned int samples;
312	u32 stats;
313	unsigned int i;
314
315	/*
316	 * Check how many samples are available. We always have to read exactly
317	 * sample_count samples from the fifo, or a multiple of sample_count.
318	 * Otherwise we mixup samples into different touch events.
319	 */
320	regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
321	samples = MX25_ADCQ_SR_FDN(stats);
322	samples -= samples % priv->sample_count;
323
324	if (!samples)
325		return IRQ_HANDLED;
326
327	for (i = 0; i != samples; ++i)
328		regmap_read(priv->regs, MX25_ADCQ_FIFO, &sample_buf[i]);
329
330	mx25_tcq_create_event_for_4wire(priv, sample_buf, samples);
331
332	return IRQ_HANDLED;
333}
334
335static irqreturn_t mx25_tcq_irq(int irq, void *dev_id)
336{
337	struct mx25_tcq_priv *priv = dev_id;
338	u32 stat;
339	int ret = IRQ_HANDLED;
340
341	regmap_read(priv->regs, MX25_ADCQ_SR, &stat);
342
343	if (stat & (MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR))
344		mx25_tcq_re_enable_touch_detection(priv);
345
346	if (stat & MX25_ADCQ_SR_PD) {
347		mx25_tcq_disable_touch_irq(priv);
348		mx25_tcq_force_queue_start(priv);
349		mx25_tcq_enable_fifo_irq(priv);
350	}
351
352	if (stat & MX25_ADCQ_SR_FDRY) {
353		mx25_tcq_disable_fifo_irq(priv);
354		ret = IRQ_WAKE_THREAD;
355	}
356
357	regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
358			   MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR |
359			   MX25_ADCQ_SR_PD,
360			   MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR |
361			   MX25_ADCQ_SR_FOR | MX25_ADCQ_SR_PD);
362
363	return ret;
364}
365
366/* configure the state machine for a 4-wire touchscreen */
367static int mx25_tcq_init(struct mx25_tcq_priv *priv)
368{
369	u32 tgcr;
370	unsigned int ipg_div;
371	unsigned int adc_period;
372	unsigned int debounce_cnt;
373	unsigned int settling_cnt;
374	int itemct;
375	int error;
376
377	regmap_read(priv->core_regs, MX25_TSC_TGCR, &tgcr);
378	ipg_div = max_t(unsigned int, 4, MX25_TGCR_GET_ADCCLK(tgcr));
379	adc_period = USEC_PER_SEC * ipg_div * 2 + 2;
380	adc_period /= clk_get_rate(priv->clk) / 1000 + 1;
381	debounce_cnt = DIV_ROUND_UP(priv->pen_debounce, adc_period * 8) - 1;
382	settling_cnt = DIV_ROUND_UP(priv->settling_time, adc_period * 8) - 1;
383
384	/* Reset */
385	regmap_write(priv->regs, MX25_ADCQ_CR,
386		     MX25_ADCQ_CR_QRST | MX25_ADCQ_CR_FRST);
387	regmap_update_bits(priv->regs, MX25_ADCQ_CR,
388			   MX25_ADCQ_CR_QRST | MX25_ADCQ_CR_FRST, 0);
389
390	/* up to 128 * 8 ADC clocks are possible */
391	if (debounce_cnt > 127)
392		debounce_cnt = 127;
393
394	/* up to 255 * 8 ADC clocks are possible */
395	if (settling_cnt > 255)
396		settling_cnt = 255;
397
398	error = imx25_setup_queue_4wire(priv, settling_cnt, &itemct);
399	if (error)
400		return error;
401
402	regmap_update_bits(priv->regs, MX25_ADCQ_CR,
403			   MX25_ADCQ_CR_LITEMID_MASK | MX25_ADCQ_CR_WMRK_MASK,
404			   MX25_ADCQ_CR_LITEMID(itemct - 1) |
405			   MX25_ADCQ_CR_WMRK(priv->expected_samples - 1));
406
407	/* setup debounce count */
408	regmap_update_bits(priv->core_regs, MX25_TSC_TGCR,
409			   MX25_TGCR_PDBTIME_MASK,
410			   MX25_TGCR_PDBTIME(debounce_cnt));
411
412	/* enable debounce */
413	regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDBEN,
414			   MX25_TGCR_PDBEN);
415	regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDEN,
416			   MX25_TGCR_PDEN);
417
418	/* enable the engine on demand */
419	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_QSM_MASK,
420			   MX25_ADCQ_CR_QSM_FQS);
421
422	/* Enable repeat and repeat wait */
423	regmap_update_bits(priv->regs, MX25_ADCQ_CR,
424			   MX25_ADCQ_CR_RPT | MX25_ADCQ_CR_RWAIT_MASK,
425			   MX25_ADCQ_CR_RPT |
426			   MX25_ADCQ_CR_RWAIT(MX25_TSC_REPEAT_WAIT));
427
428	return 0;
429}
430
431static int mx25_tcq_parse_dt(struct platform_device *pdev,
432			     struct mx25_tcq_priv *priv)
433{
434	struct device_node *np = pdev->dev.of_node;
435	u32 wires;
436	int error;
437
438	/* Setup defaults */
439	priv->pen_threshold = 500;
440	priv->sample_count = 3;
441	priv->pen_debounce = 1000000;
442	priv->settling_time = 250000;
443
444	error = of_property_read_u32(np, "fsl,wires", &wires);
445	if (error) {
446		dev_err(&pdev->dev, "Failed to find fsl,wires properties\n");
447		return error;
448	}
449
450	if (wires == 4) {
451		priv->mode = MX25_TS_4WIRE;
452	} else {
453		dev_err(&pdev->dev, "%u-wire mode not supported\n", wires);
454		return -EINVAL;
455	}
456
457	/* These are optional, we don't care about the return values */
458	of_property_read_u32(np, "fsl,pen-threshold", &priv->pen_threshold);
459	of_property_read_u32(np, "fsl,settling-time-ns", &priv->settling_time);
460	of_property_read_u32(np, "fsl,pen-debounce-ns", &priv->pen_debounce);
461
462	return 0;
463}
464
465static int mx25_tcq_open(struct input_dev *idev)
466{
467	struct device *dev = &idev->dev;
468	struct mx25_tcq_priv *priv = dev_get_drvdata(dev);
469	int error;
470
471	error = clk_prepare_enable(priv->clk);
472	if (error) {
473		dev_err(dev, "Failed to enable ipg clock\n");
474		return error;
475	}
476
477	error = mx25_tcq_init(priv);
478	if (error) {
479		dev_err(dev, "Failed to init tcq\n");
480		clk_disable_unprepare(priv->clk);
481		return error;
482	}
483
484	mx25_tcq_re_enable_touch_detection(priv);
485
486	return 0;
487}
488
489static void mx25_tcq_close(struct input_dev *idev)
490{
491	struct mx25_tcq_priv *priv = input_get_drvdata(idev);
492
493	mx25_tcq_force_queue_stop(priv);
494	mx25_tcq_disable_touch_irq(priv);
495	mx25_tcq_disable_fifo_irq(priv);
496	clk_disable_unprepare(priv->clk);
497}
498
499static int mx25_tcq_probe(struct platform_device *pdev)
500{
501	struct device *dev = &pdev->dev;
502	struct input_dev *idev;
503	struct mx25_tcq_priv *priv;
504	struct mx25_tsadc *tsadc = dev_get_drvdata(dev->parent);
505	void __iomem *mem;
506	int error;
507
508	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
509	if (!priv)
510		return -ENOMEM;
511	priv->dev = dev;
512
513	mem = devm_platform_ioremap_resource(pdev, 0);
514	if (IS_ERR(mem))
515		return PTR_ERR(mem);
516
517	error = mx25_tcq_parse_dt(pdev, priv);
518	if (error)
519		return error;
520
521	priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_tcq_regconfig);
522	if (IS_ERR(priv->regs)) {
523		dev_err(dev, "Failed to initialize regmap\n");
524		return PTR_ERR(priv->regs);
525	}
526
527	priv->irq = platform_get_irq(pdev, 0);
528	if (priv->irq <= 0)
529		return priv->irq;
530
531	idev = devm_input_allocate_device(dev);
532	if (!idev) {
533		dev_err(dev, "Failed to allocate input device\n");
534		return -ENOMEM;
535	}
536
537	idev->name = mx25_tcq_name;
538	input_set_capability(idev, EV_KEY, BTN_TOUCH);
539	input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
540	input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
541
542	idev->id.bustype = BUS_HOST;
543	idev->open = mx25_tcq_open;
544	idev->close = mx25_tcq_close;
545
546	priv->idev = idev;
547	input_set_drvdata(idev, priv);
548
549	priv->core_regs = tsadc->regs;
550	if (!priv->core_regs)
551		return -EINVAL;
552
553	priv->clk = tsadc->clk;
554	if (!priv->clk)
555		return -EINVAL;
556
557	platform_set_drvdata(pdev, priv);
558
559	error = devm_request_threaded_irq(dev, priv->irq, mx25_tcq_irq,
560					  mx25_tcq_irq_thread, 0, pdev->name,
561					  priv);
562	if (error) {
563		dev_err(dev, "Failed requesting IRQ\n");
564		return error;
565	}
566
567	error = input_register_device(idev);
568	if (error) {
569		dev_err(dev, "Failed to register input device\n");
570		return error;
571	}
572
573	return 0;
574}
575
576static struct platform_driver mx25_tcq_driver = {
577	.driver		= {
578		.name	= "mx25-tcq",
579		.of_match_table = mx25_tcq_ids,
580	},
581	.probe		= mx25_tcq_probe,
582};
583module_platform_driver(mx25_tcq_driver);
584
585MODULE_DESCRIPTION("TS input driver for Freescale mx25");
586MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
587MODULE_LICENSE("GPL v2");
~/ Read-only file preview.