blob: d812be4b61df430d84685178c56ed69849bf0175 [file] [log] [blame]
Patil, Rachna01636eb2012-10-16 12:55:43 +05301/*
2 * TI Touch Screen / ADC MFD driver
3 *
4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation version 2.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/slab.h>
19#include <linux/err.h>
20#include <linux/io.h>
21#include <linux/clk.h>
22#include <linux/regmap.h>
23#include <linux/mfd/core.h>
24#include <linux/pm_runtime.h>
25
26#include <linux/mfd/ti_am335x_tscadc.h>
Patil, Rachna2b99baf2012-10-16 12:55:44 +053027#include <linux/input/ti_am335x_tsc.h>
Patil, Rachna01636eb2012-10-16 12:55:43 +053028
29static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg)
30{
31 unsigned int val;
32
33 regmap_read(tsadc->regmap_tscadc, reg, &val);
34 return val;
35}
36
37static void tscadc_writel(struct ti_tscadc_dev *tsadc, unsigned int reg,
38 unsigned int val)
39{
40 regmap_write(tsadc->regmap_tscadc, reg, val);
41}
42
43static const struct regmap_config tscadc_regmap_config = {
44 .name = "ti_tscadc",
45 .reg_bits = 32,
46 .reg_stride = 4,
47 .val_bits = 32,
48};
49
50static void tscadc_idle_config(struct ti_tscadc_dev *config)
51{
52 unsigned int idleconfig;
53
54 idleconfig = STEPCONFIG_YNN | STEPCONFIG_INM_ADCREFM |
55 STEPCONFIG_INP_ADCREFM | STEPCONFIG_YPN;
56
57 tscadc_writel(config, REG_IDLECONFIG, idleconfig);
58}
59
60static int __devinit ti_tscadc_probe(struct platform_device *pdev)
61{
62 struct ti_tscadc_dev *tscadc;
63 struct resource *res;
64 struct clk *clk;
65 struct mfd_tscadc_board *pdata = pdev->dev.platform_data;
Patil, Rachna2b99baf2012-10-16 12:55:44 +053066 struct mfd_cell *cell;
Patil, Rachna01636eb2012-10-16 12:55:43 +053067 int irq;
68 int err, ctrl;
69 int clk_value, clock_rate;
Patil, Rachna2b99baf2012-10-16 12:55:44 +053070 int tsc_wires;
Patil, Rachna01636eb2012-10-16 12:55:43 +053071
72 if (!pdata) {
73 dev_err(&pdev->dev, "Could not find platform data\n");
74 return -EINVAL;
75 }
76
Patil, Rachna2b99baf2012-10-16 12:55:44 +053077 tsc_wires = pdata->tsc_init->wires;
78
Patil, Rachna01636eb2012-10-16 12:55:43 +053079 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
80 if (!res) {
81 dev_err(&pdev->dev, "no memory resource defined.\n");
82 return -EINVAL;
83 }
84
85 irq = platform_get_irq(pdev, 0);
86 if (irq < 0) {
87 dev_err(&pdev->dev, "no irq ID is specified.\n");
88 return -EINVAL;
89 }
90
91 /* Allocate memory for device */
92 tscadc = devm_kzalloc(&pdev->dev,
93 sizeof(struct ti_tscadc_dev), GFP_KERNEL);
94 if (!tscadc) {
95 dev_err(&pdev->dev, "failed to allocate memory.\n");
96 return -ENOMEM;
97 }
98 tscadc->dev = &pdev->dev;
99 tscadc->irq = irq;
100
101 res = devm_request_mem_region(&pdev->dev,
102 res->start, resource_size(res), pdev->name);
103 if (!res) {
104 dev_err(&pdev->dev, "failed to reserve registers.\n");
105 err = -EBUSY;
106 goto err;
107 }
108
109 tscadc->tscadc_base = devm_ioremap(&pdev->dev,
110 res->start, resource_size(res));
111 if (!tscadc->tscadc_base) {
112 dev_err(&pdev->dev, "failed to map registers.\n");
113 err = -ENOMEM;
114 goto err;
115 }
116
117 tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev,
118 tscadc->tscadc_base, &tscadc_regmap_config);
119 if (IS_ERR(tscadc->regmap_tscadc)) {
120 dev_err(&pdev->dev, "regmap init failed\n");
121 err = PTR_ERR(tscadc->regmap_tscadc);
122 goto err;
123 }
124
125 pm_runtime_enable(&pdev->dev);
126 pm_runtime_get_sync(&pdev->dev);
127
128 /*
129 * The TSC_ADC_Subsystem has 2 clock domains
130 * OCP_CLK and ADC_CLK.
131 * The ADC clock is expected to run at target of 3MHz,
132 * and expected to capture 12-bit data at a rate of 200 KSPS.
133 * The TSC_ADC_SS controller design assumes the OCP clock is
134 * at least 6x faster than the ADC clock.
135 */
136 clk = clk_get(&pdev->dev, "adc_tsc_fck");
137 if (IS_ERR(clk)) {
138 dev_err(&pdev->dev, "failed to get TSC fck\n");
139 err = PTR_ERR(clk);
140 goto err_disable_clk;
141 }
142 clock_rate = clk_get_rate(clk);
143 clk_put(clk);
144 clk_value = clock_rate / ADC_CLK;
145 if (clk_value < MAX_CLK_DIV) {
146 dev_err(&pdev->dev, "clock input less than min clock requirement\n");
147 err = -EINVAL;
148 goto err_disable_clk;
149 }
150 /* TSCADC_CLKDIV needs to be configured to the value minus 1 */
151 clk_value = clk_value - 1;
152 tscadc_writel(tscadc, REG_CLKDIV, clk_value);
153
154 /* Set the control register bits */
155 ctrl = CNTRLREG_STEPCONFIGWRT |
156 CNTRLREG_TSCENB |
157 CNTRLREG_STEPID |
158 CNTRLREG_4WIRE;
159 tscadc_writel(tscadc, REG_CTRL, ctrl);
160
161 /* Set register bits for Idle Config Mode */
162 tscadc_idle_config(tscadc);
163
164 /* Enable the TSC module enable bit */
165 ctrl = tscadc_readl(tscadc, REG_CTRL);
166 ctrl |= CNTRLREG_TSCSSENB;
167 tscadc_writel(tscadc, REG_CTRL, ctrl);
168
Patil, Rachna2b99baf2012-10-16 12:55:44 +0530169 /* TSC Cell */
170 cell = &tscadc->cells[TSC_CELL];
171 cell->name = "tsc";
172 cell->platform_data = tscadc;
173 cell->pdata_size = sizeof(*tscadc);
174
Patil, Rachna01636eb2012-10-16 12:55:43 +0530175 err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells,
176 TSCADC_CELLS, NULL, 0, NULL);
177 if (err < 0)
178 goto err_disable_clk;
179
180 device_init_wakeup(&pdev->dev, true);
181 platform_set_drvdata(pdev, tscadc);
182
183 return 0;
184
185err_disable_clk:
186 pm_runtime_put_sync(&pdev->dev);
187 pm_runtime_disable(&pdev->dev);
188err:
189 return err;
190}
191
192static int __devexit ti_tscadc_remove(struct platform_device *pdev)
193{
194 struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev);
195
196 tscadc_writel(tscadc, REG_SE, 0x00);
197
198 pm_runtime_put_sync(&pdev->dev);
199 pm_runtime_disable(&pdev->dev);
200
201 mfd_remove_devices(tscadc->dev);
202
203 return 0;
204}
205
206#ifdef CONFIG_PM
207static int tscadc_suspend(struct device *dev)
208{
209 struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev);
210
211 tscadc_writel(tscadc_dev, REG_SE, 0x00);
212 pm_runtime_put_sync(dev);
213
214 return 0;
215}
216
217static int tscadc_resume(struct device *dev)
218{
219 struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev);
220 unsigned int restore, ctrl;
221
222 pm_runtime_get_sync(dev);
223
224 /* context restore */
225 ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB |
226 CNTRLREG_STEPID | CNTRLREG_4WIRE;
227 tscadc_writel(tscadc_dev, REG_CTRL, ctrl);
228 tscadc_idle_config(tscadc_dev);
229 tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB);
230 restore = tscadc_readl(tscadc_dev, REG_CTRL);
231 tscadc_writel(tscadc_dev, REG_CTRL,
232 (restore | CNTRLREG_TSCSSENB));
233
234 return 0;
235}
236
237static const struct dev_pm_ops tscadc_pm_ops = {
238 .suspend = tscadc_suspend,
239 .resume = tscadc_resume,
240};
241#define TSCADC_PM_OPS (&tscadc_pm_ops)
242#else
243#define TSCADC_PM_OPS NULL
244#endif
245
246static struct platform_driver ti_tscadc_driver = {
247 .driver = {
248 .name = "ti_tscadc",
249 .owner = THIS_MODULE,
250 .pm = TSCADC_PM_OPS,
251 },
252 .probe = ti_tscadc_probe,
253 .remove = __devexit_p(ti_tscadc_remove),
254
255};
256
257module_platform_driver(ti_tscadc_driver);
258
259MODULE_DESCRIPTION("TI touchscreen / ADC MFD controller driver");
260MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
261MODULE_LICENSE("GPL");