2 * TI Touch Screen / ADC MFD driver
4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
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.
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.
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/slab.h>
19 #include <linux/err.h>
21 #include <linux/clk.h>
22 #include <linux/regmap.h>
23 #include <linux/mfd/core.h>
24 #include <linux/pm_runtime.h>
26 #include <linux/mfd/ti_am335x_tscadc.h>
27 #include <linux/input/ti_am335x_tsc.h>
28 #include <linux/platform_data/ti_am335x_adc.h>
30 static unsigned int tscadc_readl(struct ti_tscadc_dev
*tsadc
, unsigned int reg
)
34 regmap_read(tsadc
->regmap_tscadc
, reg
, &val
);
38 static void tscadc_writel(struct ti_tscadc_dev
*tsadc
, unsigned int reg
,
41 regmap_write(tsadc
->regmap_tscadc
, reg
, val
);
44 static const struct regmap_config tscadc_regmap_config
= {
51 static void tscadc_idle_config(struct ti_tscadc_dev
*config
)
53 unsigned int idleconfig
;
55 idleconfig
= STEPCONFIG_YNN
| STEPCONFIG_INM_ADCREFM
|
56 STEPCONFIG_INP_ADCREFM
| STEPCONFIG_YPN
;
58 tscadc_writel(config
, REG_IDLECONFIG
, idleconfig
);
61 static int ti_tscadc_probe(struct platform_device
*pdev
)
63 struct ti_tscadc_dev
*tscadc
;
66 struct mfd_tscadc_board
*pdata
= pdev
->dev
.platform_data
;
67 struct mfd_cell
*cell
;
69 int clk_value
, clock_rate
;
70 int tsc_wires
, adc_channels
= 0, total_channels
;
73 dev_err(&pdev
->dev
, "Could not find platform data\n");
78 adc_channels
= pdata
->adc_init
->adc_channels
;
80 tsc_wires
= pdata
->tsc_init
->wires
;
81 total_channels
= tsc_wires
+ adc_channels
;
83 if (total_channels
> 8) {
84 dev_err(&pdev
->dev
, "Number of i/p channels more than 8\n");
88 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
90 dev_err(&pdev
->dev
, "no memory resource defined.\n");
94 /* Allocate memory for device */
95 tscadc
= devm_kzalloc(&pdev
->dev
,
96 sizeof(struct ti_tscadc_dev
), GFP_KERNEL
);
98 dev_err(&pdev
->dev
, "failed to allocate memory.\n");
101 tscadc
->dev
= &pdev
->dev
;
103 err
= platform_get_irq(pdev
, 0);
105 dev_err(&pdev
->dev
, "no irq ID is specified.\n");
110 res
= devm_request_mem_region(&pdev
->dev
,
111 res
->start
, resource_size(res
), pdev
->name
);
113 dev_err(&pdev
->dev
, "failed to reserve registers.\n");
117 tscadc
->tscadc_base
= devm_ioremap(&pdev
->dev
,
118 res
->start
, resource_size(res
));
119 if (!tscadc
->tscadc_base
) {
120 dev_err(&pdev
->dev
, "failed to map registers.\n");
124 tscadc
->regmap_tscadc
= devm_regmap_init_mmio(&pdev
->dev
,
125 tscadc
->tscadc_base
, &tscadc_regmap_config
);
126 if (IS_ERR(tscadc
->regmap_tscadc
)) {
127 dev_err(&pdev
->dev
, "regmap init failed\n");
128 err
= PTR_ERR(tscadc
->regmap_tscadc
);
132 pm_runtime_enable(&pdev
->dev
);
133 pm_runtime_get_sync(&pdev
->dev
);
136 * The TSC_ADC_Subsystem has 2 clock domains
137 * OCP_CLK and ADC_CLK.
138 * The ADC clock is expected to run at target of 3MHz,
139 * and expected to capture 12-bit data at a rate of 200 KSPS.
140 * The TSC_ADC_SS controller design assumes the OCP clock is
141 * at least 6x faster than the ADC clock.
143 clk
= clk_get(&pdev
->dev
, "adc_tsc_fck");
145 dev_err(&pdev
->dev
, "failed to get TSC fck\n");
147 goto err_disable_clk
;
149 clock_rate
= clk_get_rate(clk
);
151 clk_value
= clock_rate
/ ADC_CLK
;
152 if (clk_value
< MAX_CLK_DIV
) {
153 dev_err(&pdev
->dev
, "clock input less than min clock requirement\n");
155 goto err_disable_clk
;
157 /* TSCADC_CLKDIV needs to be configured to the value minus 1 */
158 clk_value
= clk_value
- 1;
159 tscadc_writel(tscadc
, REG_CLKDIV
, clk_value
);
161 /* Set the control register bits */
162 ctrl
= CNTRLREG_STEPCONFIGWRT
|
166 tscadc_writel(tscadc
, REG_CTRL
, ctrl
);
168 /* Set register bits for Idle Config Mode */
169 tscadc_idle_config(tscadc
);
171 /* Enable the TSC module enable bit */
172 ctrl
= tscadc_readl(tscadc
, REG_CTRL
);
173 ctrl
|= CNTRLREG_TSCSSENB
;
174 tscadc_writel(tscadc
, REG_CTRL
, ctrl
);
177 cell
= &tscadc
->cells
[TSC_CELL
];
179 cell
->platform_data
= tscadc
;
180 cell
->pdata_size
= sizeof(*tscadc
);
183 cell
= &tscadc
->cells
[ADC_CELL
];
184 cell
->name
= "tiadc";
185 cell
->platform_data
= tscadc
;
186 cell
->pdata_size
= sizeof(*tscadc
);
188 err
= mfd_add_devices(&pdev
->dev
, pdev
->id
, tscadc
->cells
,
189 TSCADC_CELLS
, NULL
, 0, NULL
);
191 goto err_disable_clk
;
193 device_init_wakeup(&pdev
->dev
, true);
194 platform_set_drvdata(pdev
, tscadc
);
199 pm_runtime_put_sync(&pdev
->dev
);
200 pm_runtime_disable(&pdev
->dev
);
205 static int ti_tscadc_remove(struct platform_device
*pdev
)
207 struct ti_tscadc_dev
*tscadc
= platform_get_drvdata(pdev
);
209 tscadc_writel(tscadc
, REG_SE
, 0x00);
211 pm_runtime_put_sync(&pdev
->dev
);
212 pm_runtime_disable(&pdev
->dev
);
214 mfd_remove_devices(tscadc
->dev
);
220 static int tscadc_suspend(struct device
*dev
)
222 struct ti_tscadc_dev
*tscadc_dev
= dev_get_drvdata(dev
);
224 tscadc_writel(tscadc_dev
, REG_SE
, 0x00);
225 pm_runtime_put_sync(dev
);
230 static int tscadc_resume(struct device
*dev
)
232 struct ti_tscadc_dev
*tscadc_dev
= dev_get_drvdata(dev
);
233 unsigned int restore
, ctrl
;
235 pm_runtime_get_sync(dev
);
237 /* context restore */
238 ctrl
= CNTRLREG_STEPCONFIGWRT
| CNTRLREG_TSCENB
|
239 CNTRLREG_STEPID
| CNTRLREG_4WIRE
;
240 tscadc_writel(tscadc_dev
, REG_CTRL
, ctrl
);
241 tscadc_idle_config(tscadc_dev
);
242 tscadc_writel(tscadc_dev
, REG_SE
, STPENB_STEPENB
);
243 restore
= tscadc_readl(tscadc_dev
, REG_CTRL
);
244 tscadc_writel(tscadc_dev
, REG_CTRL
,
245 (restore
| CNTRLREG_TSCSSENB
));
250 static const struct dev_pm_ops tscadc_pm_ops
= {
251 .suspend
= tscadc_suspend
,
252 .resume
= tscadc_resume
,
254 #define TSCADC_PM_OPS (&tscadc_pm_ops)
256 #define TSCADC_PM_OPS NULL
259 static struct platform_driver ti_tscadc_driver
= {
262 .owner
= THIS_MODULE
,
265 .probe
= ti_tscadc_probe
,
266 .remove
= ti_tscadc_remove
,
270 module_platform_driver(ti_tscadc_driver
);
272 MODULE_DESCRIPTION("TI touchscreen / ADC MFD controller driver");
273 MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
274 MODULE_LICENSE("GPL");