13bda759fSMiquel Raynal // SPDX-License-Identifier: GPL-2.0-only
201636eb9SPatil, Rachna /*
301636eb9SPatil, Rachna  * TI Touch Screen / ADC MFD driver
401636eb9SPatil, Rachna  *
54f4ed454SAlexander A. Klimov  * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
601636eb9SPatil, Rachna  */
701636eb9SPatil, Rachna 
801636eb9SPatil, Rachna #include <linux/module.h>
901636eb9SPatil, Rachna #include <linux/slab.h>
1001636eb9SPatil, Rachna #include <linux/err.h>
1101636eb9SPatil, Rachna #include <linux/io.h>
1201636eb9SPatil, Rachna #include <linux/clk.h>
1301636eb9SPatil, Rachna #include <linux/regmap.h>
1401636eb9SPatil, Rachna #include <linux/mfd/core.h>
1501636eb9SPatil, Rachna #include <linux/pm_runtime.h>
16a6543a1cSPatil, Rachna #include <linux/of.h>
17*dc0c386eSRob Herring #include <linux/platform_device.h>
187ca6740cSSebastian Andrzej Siewior #include <linux/sched.h>
1901636eb9SPatil, Rachna 
2001636eb9SPatil, Rachna #include <linux/mfd/ti_am335x_tscadc.h>
2101636eb9SPatil, Rachna 
2201636eb9SPatil, Rachna static const struct regmap_config tscadc_regmap_config = {
2301636eb9SPatil, Rachna 	.name = "ti_tscadc",
2401636eb9SPatil, Rachna 	.reg_bits = 32,
2501636eb9SPatil, Rachna 	.reg_stride = 4,
2601636eb9SPatil, Rachna 	.val_bits = 32,
2701636eb9SPatil, Rachna };
2801636eb9SPatil, Rachna 
am335x_tsc_se_set_cache(struct ti_tscadc_dev * tscadc,u32 val)29a318b7d0SAndrew F. Davis void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tscadc, u32 val)
30abeccee4SPatil, Rachna {
31317b2099SSebastian Andrzej Siewior 	unsigned long flags;
32317b2099SSebastian Andrzej Siewior 
33a318b7d0SAndrew F. Davis 	spin_lock_irqsave(&tscadc->reg_lock, flags);
34a318b7d0SAndrew F. Davis 	tscadc->reg_se_cache |= val;
35a318b7d0SAndrew F. Davis 	if (tscadc->adc_waiting)
36a318b7d0SAndrew F. Davis 		wake_up(&tscadc->reg_se_wait);
37a318b7d0SAndrew F. Davis 	else if (!tscadc->adc_in_use)
380d3a7cceSAndrew F. Davis 		regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache);
397ca6740cSSebastian Andrzej Siewior 
40a318b7d0SAndrew F. Davis 	spin_unlock_irqrestore(&tscadc->reg_lock, flags);
41abeccee4SPatil, Rachna }
427e170c6eSSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache);
437e170c6eSSebastian Andrzej Siewior 
am335x_tscadc_need_adc(struct ti_tscadc_dev * tscadc)44a318b7d0SAndrew F. Davis static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tscadc)
457ca6740cSSebastian Andrzej Siewior {
467ca6740cSSebastian Andrzej Siewior 	DEFINE_WAIT(wait);
477ca6740cSSebastian Andrzej Siewior 	u32 reg;
487ca6740cSSebastian Andrzej Siewior 
490d3a7cceSAndrew F. Davis 	regmap_read(tscadc->regmap, REG_ADCFSM, &reg);
507ca6740cSSebastian Andrzej Siewior 	if (reg & SEQ_STATUS) {
51a318b7d0SAndrew F. Davis 		tscadc->adc_waiting = true;
52a318b7d0SAndrew F. Davis 		prepare_to_wait(&tscadc->reg_se_wait, &wait,
537ca6740cSSebastian Andrzej Siewior 				TASK_UNINTERRUPTIBLE);
54a318b7d0SAndrew F. Davis 		spin_unlock_irq(&tscadc->reg_lock);
557ca6740cSSebastian Andrzej Siewior 
567ca6740cSSebastian Andrzej Siewior 		schedule();
577ca6740cSSebastian Andrzej Siewior 
58a318b7d0SAndrew F. Davis 		spin_lock_irq(&tscadc->reg_lock);
59a318b7d0SAndrew F. Davis 		finish_wait(&tscadc->reg_se_wait, &wait);
607ca6740cSSebastian Andrzej Siewior 
61b10848e6SVignesh R 		/*
62b10848e6SVignesh R 		 * Sequencer should either be idle or
63b10848e6SVignesh R 		 * busy applying the charge step.
64b10848e6SVignesh R 		 */
650d3a7cceSAndrew F. Davis 		regmap_read(tscadc->regmap, REG_ADCFSM, &reg);
66b10848e6SVignesh R 		WARN_ON((reg & SEQ_STATUS) && !(reg & CHARGE_STEP));
67a318b7d0SAndrew F. Davis 		tscadc->adc_waiting = false;
687ca6740cSSebastian Andrzej Siewior 	}
69a318b7d0SAndrew F. Davis 	tscadc->adc_in_use = true;
707ca6740cSSebastian Andrzej Siewior }
717ca6740cSSebastian Andrzej Siewior 
am335x_tsc_se_set_once(struct ti_tscadc_dev * tscadc,u32 val)72a318b7d0SAndrew F. Davis void am335x_tsc_se_set_once(struct ti_tscadc_dev *tscadc, u32 val)
737e170c6eSSebastian Andrzej Siewior {
74a318b7d0SAndrew F. Davis 	spin_lock_irq(&tscadc->reg_lock);
75a318b7d0SAndrew F. Davis 	am335x_tscadc_need_adc(tscadc);
767ca6740cSSebastian Andrzej Siewior 
770d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_SE, val);
78a318b7d0SAndrew F. Davis 	spin_unlock_irq(&tscadc->reg_lock);
797ca6740cSSebastian Andrzej Siewior }
807ca6740cSSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once);
817ca6740cSSebastian Andrzej Siewior 
am335x_tsc_se_adc_done(struct ti_tscadc_dev * tscadc)82a318b7d0SAndrew F. Davis void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tscadc)
837ca6740cSSebastian Andrzej Siewior {
847e170c6eSSebastian Andrzej Siewior 	unsigned long flags;
857e170c6eSSebastian Andrzej Siewior 
86a318b7d0SAndrew F. Davis 	spin_lock_irqsave(&tscadc->reg_lock, flags);
87a318b7d0SAndrew F. Davis 	tscadc->adc_in_use = false;
880d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache);
89a318b7d0SAndrew F. Davis 	spin_unlock_irqrestore(&tscadc->reg_lock, flags);
907e170c6eSSebastian Andrzej Siewior }
917ca6740cSSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(am335x_tsc_se_adc_done);
92abeccee4SPatil, Rachna 
am335x_tsc_se_clr(struct ti_tscadc_dev * tscadc,u32 val)93a318b7d0SAndrew F. Davis void am335x_tsc_se_clr(struct ti_tscadc_dev *tscadc, u32 val)
94abeccee4SPatil, Rachna {
95317b2099SSebastian Andrzej Siewior 	unsigned long flags;
96317b2099SSebastian Andrzej Siewior 
97a318b7d0SAndrew F. Davis 	spin_lock_irqsave(&tscadc->reg_lock, flags);
98a318b7d0SAndrew F. Davis 	tscadc->reg_se_cache &= ~val;
990d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache);
100a318b7d0SAndrew F. Davis 	spin_unlock_irqrestore(&tscadc->reg_lock, flags);
101abeccee4SPatil, Rachna }
102abeccee4SPatil, Rachna EXPORT_SYMBOL_GPL(am335x_tsc_se_clr);
103abeccee4SPatil, Rachna 
tscadc_idle_config(struct ti_tscadc_dev * tscadc)104a318b7d0SAndrew F. Davis static void tscadc_idle_config(struct ti_tscadc_dev *tscadc)
10501636eb9SPatil, Rachna {
10601636eb9SPatil, Rachna 	unsigned int idleconfig;
10701636eb9SPatil, Rachna 
108bf0f394cSMiquel Raynal 	idleconfig = STEPCONFIG_INM_ADCREFM | STEPCONFIG_INP_ADCREFM;
109bf0f394cSMiquel Raynal 	if (ti_adc_with_touchscreen(tscadc))
110bf0f394cSMiquel Raynal 		idleconfig |= STEPCONFIG_YNN | STEPCONFIG_YPN;
11101636eb9SPatil, Rachna 
1120d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_IDLECONFIG, idleconfig);
11301636eb9SPatil, Rachna }
11401636eb9SPatil, Rachna 
ti_tscadc_probe(struct platform_device * pdev)115612b95cdSGreg Kroah-Hartman static	int ti_tscadc_probe(struct platform_device *pdev)
11601636eb9SPatil, Rachna {
11701636eb9SPatil, Rachna 	struct ti_tscadc_dev *tscadc;
11801636eb9SPatil, Rachna 	struct resource *res;
11901636eb9SPatil, Rachna 	struct clk *clk;
120e368866eSColin Ian King 	struct device_node *node;
1212b99bafaSPatil, Rachna 	struct mfd_cell *cell;
12218926edeSSebastian Andrzej Siewior 	struct property *prop;
12318926edeSSebastian Andrzej Siewior 	const __be32 *cur;
1240a123303SMiquel Raynal 	bool use_tsc = false, use_mag = false;
12518926edeSSebastian Andrzej Siewior 	u32 val;
126b813f320SMiquel Raynal 	int err;
127430b98fcSMiquel Raynal 	int tscmag_wires = 0, adc_channels = 0, cell_idx = 0, total_channels;
1280a123303SMiquel Raynal 	int readouts = 0, mag_tracks = 0;
12901636eb9SPatil, Rachna 
13061479479SMiquel Raynal 	/* Allocate memory for device */
13161479479SMiquel Raynal 	tscadc = devm_kzalloc(&pdev->dev, sizeof(*tscadc), GFP_KERNEL);
13261479479SMiquel Raynal 	if (!tscadc)
13361479479SMiquel Raynal 		return -ENOMEM;
13461479479SMiquel Raynal 
13561479479SMiquel Raynal 	tscadc->dev = &pdev->dev;
13661479479SMiquel Raynal 
1379e5775f3SSebastian Andrzej Siewior 	if (!pdev->dev.of_node) {
1389e5775f3SSebastian Andrzej Siewior 		dev_err(&pdev->dev, "Could not find valid DT data.\n");
13901636eb9SPatil, Rachna 		return -EINVAL;
14001636eb9SPatil, Rachna 	}
14101636eb9SPatil, Rachna 
142f7834843SMiquel Raynal 	tscadc->data = of_device_get_match_data(&pdev->dev);
143f7834843SMiquel Raynal 
144bf0f394cSMiquel Raynal 	if (ti_adc_with_touchscreen(tscadc)) {
145a6543a1cSPatil, Rachna 		node = of_get_child_by_name(pdev->dev.of_node, "tsc");
146430b98fcSMiquel Raynal 		of_property_read_u32(node, "ti,wires", &tscmag_wires);
14790fc6ff4SMiquel Raynal 		err = of_property_read_u32(node, "ti,coordinate-readouts",
14890fc6ff4SMiquel Raynal 					   &readouts);
14990fc6ff4SMiquel Raynal 		if (err < 0)
15090fc6ff4SMiquel Raynal 			of_property_read_u32(node, "ti,coordiante-readouts",
15190fc6ff4SMiquel Raynal 					     &readouts);
15290fc6ff4SMiquel Raynal 
15329f95e8bSMiquel Raynal 		of_node_put(node);
15490fc6ff4SMiquel Raynal 
1552a4e333aSMiquel Raynal 		if (tscmag_wires)
1562a4e333aSMiquel Raynal 			use_tsc = true;
1570a123303SMiquel Raynal 	} else {
1580a123303SMiquel Raynal 		/*
1590a123303SMiquel Raynal 		 * When adding support for the magnetic stripe reader, here is
1600a123303SMiquel Raynal 		 * the place to look for the number of tracks used from device
1610a123303SMiquel Raynal 		 * tree. Let's default to 0 for now.
1620a123303SMiquel Raynal 		 */
1630a123303SMiquel Raynal 		mag_tracks = 0;
1640a123303SMiquel Raynal 		tscmag_wires = mag_tracks * 2;
1650a123303SMiquel Raynal 		if (tscmag_wires)
1660a123303SMiquel Raynal 			use_mag = true;
167bf0f394cSMiquel Raynal 	}
1685e53a69bSPatil, Rachna 
169a6543a1cSPatil, Rachna 	node = of_get_child_by_name(pdev->dev.of_node, "adc");
17018926edeSSebastian Andrzej Siewior 	of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
17118926edeSSebastian Andrzej Siewior 		adc_channels++;
17218926edeSSebastian Andrzej Siewior 		if (val > 7) {
17318926edeSSebastian Andrzej Siewior 			dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n",
17418926edeSSebastian Andrzej Siewior 				val);
17529f95e8bSMiquel Raynal 			of_node_put(node);
17618926edeSSebastian Andrzej Siewior 			return -EINVAL;
17718926edeSSebastian Andrzej Siewior 		}
17818926edeSSebastian Andrzej Siewior 	}
17929f95e8bSMiquel Raynal 
18029f95e8bSMiquel Raynal 	of_node_put(node);
18129f95e8bSMiquel Raynal 
182430b98fcSMiquel Raynal 	total_channels = tscmag_wires + adc_channels;
1835e53a69bSPatil, Rachna 	if (total_channels > 8) {
1845e53a69bSPatil, Rachna 		dev_err(&pdev->dev, "Number of i/p channels more than 8\n");
1855e53a69bSPatil, Rachna 		return -EINVAL;
1865e53a69bSPatil, Rachna 	}
187243e3cb9SMiquel Raynal 
18824d5c82fSPantelis Antoniou 	if (total_channels == 0) {
18924d5c82fSPantelis Antoniou 		dev_err(&pdev->dev, "Need at least one channel.\n");
19024d5c82fSPantelis Antoniou 		return -EINVAL;
19124d5c82fSPantelis Antoniou 	}
1922b99bafaSPatil, Rachna 
1932a4e333aSMiquel Raynal 	if (use_tsc && (readouts * 2 + 2 + adc_channels > 16)) {
19418926edeSSebastian Andrzej Siewior 		dev_err(&pdev->dev, "Too many step configurations requested\n");
19518926edeSSebastian Andrzej Siewior 		return -EINVAL;
19618926edeSSebastian Andrzej Siewior 	}
19718926edeSSebastian Andrzej Siewior 
1983c39c9c6SPatil, Rachna 	err = platform_get_irq(pdev, 0);
199bc239d8dSTang Bin 	if (err < 0)
200287ee127SMiquel Raynal 		return err;
201bc239d8dSTang Bin 	else
2023c39c9c6SPatil, Rachna 		tscadc->irq = err;
20301636eb9SPatil, Rachna 
20407141cfeSYangtao Li 	tscadc->tscadc_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
205924ff918SJingoo Han 	if (IS_ERR(tscadc->tscadc_base))
206924ff918SJingoo Han 		return PTR_ERR(tscadc->tscadc_base);
20701636eb9SPatil, Rachna 
208de98a43eSVignesh Raghavendra 	tscadc->tscadc_phys_base = res->start;
2090d3a7cceSAndrew F. Davis 	tscadc->regmap = devm_regmap_init_mmio(&pdev->dev,
210243e3cb9SMiquel Raynal 					       tscadc->tscadc_base,
211243e3cb9SMiquel Raynal 					       &tscadc_regmap_config);
2120d3a7cceSAndrew F. Davis 	if (IS_ERR(tscadc->regmap)) {
21301636eb9SPatil, Rachna 		dev_err(&pdev->dev, "regmap init failed\n");
214287ee127SMiquel Raynal 		return PTR_ERR(tscadc->regmap);
21501636eb9SPatil, Rachna 	}
21601636eb9SPatil, Rachna 
217abeccee4SPatil, Rachna 	spin_lock_init(&tscadc->reg_lock);
2187ca6740cSSebastian Andrzej Siewior 	init_waitqueue_head(&tscadc->reg_se_wait);
2197ca6740cSSebastian Andrzej Siewior 
22001636eb9SPatil, Rachna 	pm_runtime_enable(&pdev->dev);
22101636eb9SPatil, Rachna 	pm_runtime_get_sync(&pdev->dev);
22201636eb9SPatil, Rachna 
22301636eb9SPatil, Rachna 	/*
224c4359f75SMiquel Raynal 	 * The TSC_ADC_Subsystem has 2 clock domains: OCP_CLK and ADC_CLK.
225c4359f75SMiquel Raynal 	 * ADCs produce a 12-bit sample every 15 ADC_CLK cycles.
226c4359f75SMiquel Raynal 	 * am33xx ADCs expect to capture 200ksps.
2270a123303SMiquel Raynal 	 * am47xx ADCs expect to capture 867ksps.
2280a123303SMiquel Raynal 	 * We need ADC clocks respectively running at 3MHz and 13MHz.
2290a123303SMiquel Raynal 	 * These frequencies are valid since TSC_ADC_SS controller design
230c4359f75SMiquel Raynal 	 * assumes the OCP clock is at least 6x faster than the ADC clock.
23101636eb9SPatil, Rachna 	 */
232235a96e9SMiquel Raynal 	clk = devm_clk_get(&pdev->dev, NULL);
23301636eb9SPatil, Rachna 	if (IS_ERR(clk)) {
234e40b5971SMiquel Raynal 		dev_err(&pdev->dev, "failed to get fck\n");
23501636eb9SPatil, Rachna 		err = PTR_ERR(clk);
23601636eb9SPatil, Rachna 		goto err_disable_clk;
23701636eb9SPatil, Rachna 	}
238efe3126aSPatil, Rachna 
239f7834843SMiquel Raynal 	tscadc->clk_div = (clk_get_rate(clk) / tscadc->data->target_clk_rate) - 1;
2400d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div);
24101636eb9SPatil, Rachna 
242b813f320SMiquel Raynal 	/*
243b813f320SMiquel Raynal 	 * Set the control register bits. tscadc->ctrl stores the configuration
244b813f320SMiquel Raynal 	 * of the CTRL register but not the subsystem enable bit which must be
245b813f320SMiquel Raynal 	 * added manually when timely.
246b813f320SMiquel Raynal 	 */
247bf0f394cSMiquel Raynal 	tscadc->ctrl = CNTRLREG_STEPID;
248bf0f394cSMiquel Raynal 	if (ti_adc_with_touchscreen(tscadc)) {
249bf0f394cSMiquel Raynal 		tscadc->ctrl |= CNTRLREG_TSC_STEPCONFIGWRT;
2502a4e333aSMiquel Raynal 		if (use_tsc) {
2512f89c261SMiquel Raynal 			tscadc->ctrl |= CNTRLREG_TSC_ENB;
252430b98fcSMiquel Raynal 			if (tscmag_wires == 5)
2532f89c261SMiquel Raynal 				tscadc->ctrl |= CNTRLREG_TSC_5WIRE;
254f0933a60SJeff Lance 			else
2552f89c261SMiquel Raynal 				tscadc->ctrl |= CNTRLREG_TSC_4WIRE;
256f0933a60SJeff Lance 		}
2570a123303SMiquel Raynal 	} else {
2580a123303SMiquel Raynal 		tscadc->ctrl |= CNTRLREG_MAG_PREAMP_PWRDOWN |
2590a123303SMiquel Raynal 				CNTRLREG_MAG_PREAMP_BYPASS;
260bf0f394cSMiquel Raynal 	}
261b813f320SMiquel Raynal 	regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl);
26201636eb9SPatil, Rachna 
26325b15d04SMiquel Raynal 	tscadc_idle_config(tscadc);
26425b15d04SMiquel Raynal 
26501636eb9SPatil, Rachna 	/* Enable the TSC module enable bit */
266c3e36b5dSMiquel Raynal 	regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl | CNTRLREG_SSENB);
26701636eb9SPatil, Rachna 
2680a123303SMiquel Raynal 	/* TSC or MAG Cell */
2690a123303SMiquel Raynal 	if (use_tsc || use_mag) {
2707c605802SMiquel Raynal 		cell = &tscadc->cells[cell_idx++];
271f7834843SMiquel Raynal 		cell->name = tscadc->data->secondary_feature_name;
272f7834843SMiquel Raynal 		cell->of_compatible = tscadc->data->secondary_feature_compatible;
273a9bce1b0SSebastian Andrzej Siewior 		cell->platform_data = &tscadc;
274a9bce1b0SSebastian Andrzej Siewior 		cell->pdata_size = sizeof(tscadc);
27524d5c82fSPantelis Antoniou 	}
2762b99bafaSPatil, Rachna 
2775e53a69bSPatil, Rachna 	/* ADC Cell */
27824d5c82fSPantelis Antoniou 	if (adc_channels > 0) {
2797c605802SMiquel Raynal 		cell = &tscadc->cells[cell_idx++];
280f7834843SMiquel Raynal 		cell->name = tscadc->data->adc_feature_name;
281f7834843SMiquel Raynal 		cell->of_compatible = tscadc->data->adc_feature_compatible;
282a9bce1b0SSebastian Andrzej Siewior 		cell->platform_data = &tscadc;
283a9bce1b0SSebastian Andrzej Siewior 		cell->pdata_size = sizeof(tscadc);
28424d5c82fSPantelis Antoniou 	}
2855e53a69bSPatil, Rachna 
286b40ee006SVignesh R 	err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
2877c605802SMiquel Raynal 			      tscadc->cells, cell_idx, NULL, 0, NULL);
28801636eb9SPatil, Rachna 	if (err < 0)
28901636eb9SPatil, Rachna 		goto err_disable_clk;
29001636eb9SPatil, Rachna 
29101636eb9SPatil, Rachna 	platform_set_drvdata(pdev, tscadc);
29201636eb9SPatil, Rachna 	return 0;
29301636eb9SPatil, Rachna 
29401636eb9SPatil, Rachna err_disable_clk:
29501636eb9SPatil, Rachna 	pm_runtime_put_sync(&pdev->dev);
29601636eb9SPatil, Rachna 	pm_runtime_disable(&pdev->dev);
297287ee127SMiquel Raynal 
29801636eb9SPatil, Rachna 	return err;
29901636eb9SPatil, Rachna }
30001636eb9SPatil, Rachna 
ti_tscadc_remove(struct platform_device * pdev)301612b95cdSGreg Kroah-Hartman static int ti_tscadc_remove(struct platform_device *pdev)
30201636eb9SPatil, Rachna {
30301636eb9SPatil, Rachna 	struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev);
30401636eb9SPatil, Rachna 
3050d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_SE, 0x00);
30601636eb9SPatil, Rachna 
30701636eb9SPatil, Rachna 	pm_runtime_put_sync(&pdev->dev);
30801636eb9SPatil, Rachna 	pm_runtime_disable(&pdev->dev);
30901636eb9SPatil, Rachna 
31001636eb9SPatil, Rachna 	mfd_remove_devices(tscadc->dev);
31101636eb9SPatil, Rachna 
31201636eb9SPatil, Rachna 	return 0;
31301636eb9SPatil, Rachna }
31401636eb9SPatil, Rachna 
ti_tscadc_can_wakeup(struct device * dev,void * data)315c974ac77SVignesh R static int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data)
316c974ac77SVignesh R {
317c974ac77SVignesh R 	return device_may_wakeup(dev);
318c974ac77SVignesh R }
319c974ac77SVignesh R 
tscadc_suspend(struct device * dev)320dae936a0SAndrew F. Davis static int __maybe_unused tscadc_suspend(struct device *dev)
32101636eb9SPatil, Rachna {
322a318b7d0SAndrew F. Davis 	struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev);
32301636eb9SPatil, Rachna 
3240d3a7cceSAndrew F. Davis 	regmap_write(tscadc->regmap, REG_SE, 0x00);
325c974ac77SVignesh R 	if (device_for_each_child(dev, NULL, ti_tscadc_can_wakeup)) {
326c974ac77SVignesh R 		u32 ctrl;
327c974ac77SVignesh R 
328c974ac77SVignesh R 		regmap_read(tscadc->regmap, REG_CTRL, &ctrl);
329c974ac77SVignesh R 		ctrl &= ~(CNTRLREG_POWERDOWN);
330c3e36b5dSMiquel Raynal 		ctrl |= CNTRLREG_SSENB;
331c974ac77SVignesh R 		regmap_write(tscadc->regmap, REG_CTRL, ctrl);
332c974ac77SVignesh R 	}
33301636eb9SPatil, Rachna 	pm_runtime_put_sync(dev);
33401636eb9SPatil, Rachna 
33501636eb9SPatil, Rachna 	return 0;
33601636eb9SPatil, Rachna }
33701636eb9SPatil, Rachna 
tscadc_resume(struct device * dev)338dae936a0SAndrew F. Davis static int __maybe_unused tscadc_resume(struct device *dev)
33901636eb9SPatil, Rachna {
340a318b7d0SAndrew F. Davis 	struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev);
34101636eb9SPatil, Rachna 
34201636eb9SPatil, Rachna 	pm_runtime_get_sync(dev);
34301636eb9SPatil, Rachna 
3443dafbe93SMiquel Raynal 	regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div);
345b813f320SMiquel Raynal 	regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl);
34625b15d04SMiquel Raynal 	tscadc_idle_config(tscadc);
347c3e36b5dSMiquel Raynal 	regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl | CNTRLREG_SSENB);
34801636eb9SPatil, Rachna 
34901636eb9SPatil, Rachna 	return 0;
35001636eb9SPatil, Rachna }
35101636eb9SPatil, Rachna 
352dae936a0SAndrew F. Davis static SIMPLE_DEV_PM_OPS(tscadc_pm_ops, tscadc_suspend, tscadc_resume);
35301636eb9SPatil, Rachna 
354f7834843SMiquel Raynal static const struct ti_tscadc_data tscdata = {
355f7834843SMiquel Raynal 	.adc_feature_name = "TI-am335x-adc",
356f7834843SMiquel Raynal 	.adc_feature_compatible = "ti,am3359-adc",
357f7834843SMiquel Raynal 	.secondary_feature_name = "TI-am335x-tsc",
358f7834843SMiquel Raynal 	.secondary_feature_compatible = "ti,am3359-tsc",
3592f89c261SMiquel Raynal 	.target_clk_rate = TSC_ADC_CLK,
360f7834843SMiquel Raynal };
361f7834843SMiquel Raynal 
3620a123303SMiquel Raynal static const struct ti_tscadc_data magdata = {
3630a123303SMiquel Raynal 	.adc_feature_name = "TI-am43xx-adc",
3640a123303SMiquel Raynal 	.adc_feature_compatible = "ti,am4372-adc",
3650a123303SMiquel Raynal 	.secondary_feature_name = "TI-am43xx-mag",
3660a123303SMiquel Raynal 	.secondary_feature_compatible = "ti,am4372-mag",
3670a123303SMiquel Raynal 	.target_clk_rate = MAG_ADC_CLK,
3680a123303SMiquel Raynal };
3690a123303SMiquel Raynal 
370a6543a1cSPatil, Rachna static const struct of_device_id ti_tscadc_dt_ids[] = {
371f7834843SMiquel Raynal 	{ .compatible = "ti,am3359-tscadc", .data = &tscdata },
3720a123303SMiquel Raynal 	{ .compatible = "ti,am4372-magadc", .data = &magdata },
373a6543a1cSPatil, Rachna 	{ }
374a6543a1cSPatil, Rachna };
375a6543a1cSPatil, Rachna MODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids);
376a6543a1cSPatil, Rachna 
37701636eb9SPatil, Rachna static struct platform_driver ti_tscadc_driver = {
37801636eb9SPatil, Rachna 	.driver = {
379a6543a1cSPatil, Rachna 		.name   = "ti_am3359-tscadc",
380dae936a0SAndrew F. Davis 		.pm	= &tscadc_pm_ops,
381131221bcSSachin Kamat 		.of_match_table = ti_tscadc_dt_ids,
38201636eb9SPatil, Rachna 	},
38301636eb9SPatil, Rachna 	.probe	= ti_tscadc_probe,
384612b95cdSGreg Kroah-Hartman 	.remove	= ti_tscadc_remove,
38501636eb9SPatil, Rachna 
38601636eb9SPatil, Rachna };
38701636eb9SPatil, Rachna 
38801636eb9SPatil, Rachna module_platform_driver(ti_tscadc_driver);
38901636eb9SPatil, Rachna 
3900a123303SMiquel Raynal MODULE_DESCRIPTION("TI touchscreen/magnetic stripe reader/ADC MFD controller driver");
39101636eb9SPatil, Rachna MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
39201636eb9SPatil, Rachna MODULE_LICENSE("GPL");
393