diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-04 21:36:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-04 21:36:12 -0400 |
commit | 53ee983378ff23e8f3ff95ecf99dea7c6c221900 (patch) | |
tree | 85e09b2bf6317a155f1405be0d45c69051b6e041 /drivers/iio/adc/exynos_adc.c | |
parent | 29b88e23a9212136d39b0161a39afe587d0170a5 (diff) | |
parent | b9aaea39f65e242303103b5283abeaefd8e538a4 (diff) |
Merge tag 'staging-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging driver updates from Greg KH:
"Here's the big pull request for the staging driver tree for 3.17-rc1.
Lots of things in here, over 2000 patches, but the best part is this:
1480 files changed, 39070 insertions(+), 254659 deletions(-)
Thanks to the great work of Kristina Martšenko, 14 different staging
drivers have been removed from the tree as they were obsolete and no
one was willing to work on cleaning them up. Other than the driver
removals, loads of cleanups are in here (comedi, lustre, etc.) as well
as the usual IIO driver updates and additions.
All of this has been in the linux-next tree for a while"
* tag 'staging-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (2199 commits)
staging: comedi: addi_apci_1564: remove diagnostic interrupt support code
staging: comedi: addi_apci_1564: add subdevice to check diagnostic status
staging: wlan-ng: coding style problem fix
staging: wlan-ng: fixing coding style problems
staging: comedi: ii_pci20kc: request and ioremap memory
staging: lustre: bitwise vs logical typo
staging: dgnc: Remove unneeded dgnc_trace.c and dgnc_trace.h
staging: dgnc: rephrase comment
staging: comedi: ni_tio: remove some dead code
staging: rtl8723au: Fix static symbol sparse warning
staging: rtl8723au: usb_dvobj_init(): Remove unused variable 'pdev_desc'
staging: rtl8723au: Do not duplicate kernel provided USB macros
staging: rtl8723au: Remove never set struct pwrctrl_priv.bHWPowerdown
staging: rtl8723au: Remove two never set variables
staging: rtl8723au: RSSI_test is never set
staging:r8190: coding style: Fixed checkpatch reported Error
staging:r8180: coding style: Fixed too long lines
staging:r8180: coding style: Fixed commenting style
staging: lustre: ptlrpc: lproc_ptlrpc.c - fix dereferenceing user space buffer
staging: lustre: ldlm: ldlm_resource.c - fix dereferenceing user space buffer
...
Diffstat (limited to 'drivers/iio/adc/exynos_adc.c')
-rw-r--r-- | drivers/iio/adc/exynos_adc.c | 335 |
1 files changed, 249 insertions, 86 deletions
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 010578f1d762..fc9dfc23ecb7 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/errno.h> | ||
27 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | #include <linux/io.h> | 30 | #include <linux/io.h> |
@@ -39,11 +40,6 @@ | |||
39 | #include <linux/iio/machine.h> | 40 | #include <linux/iio/machine.h> |
40 | #include <linux/iio/driver.h> | 41 | #include <linux/iio/driver.h> |
41 | 42 | ||
42 | enum adc_version { | ||
43 | ADC_V1, | ||
44 | ADC_V2 | ||
45 | }; | ||
46 | |||
47 | /* EXYNOS4412/5250 ADC_V1 registers definitions */ | 43 | /* EXYNOS4412/5250 ADC_V1 registers definitions */ |
48 | #define ADC_V1_CON(x) ((x) + 0x00) | 44 | #define ADC_V1_CON(x) ((x) + 0x00) |
49 | #define ADC_V1_DLY(x) ((x) + 0x08) | 45 | #define ADC_V1_DLY(x) ((x) + 0x08) |
@@ -75,8 +71,9 @@ enum adc_version { | |||
75 | #define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0) | 71 | #define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0) |
76 | #define ADC_V2_CON2_ACH_MASK 0xF | 72 | #define ADC_V2_CON2_ACH_MASK 0xF |
77 | 73 | ||
78 | #define MAX_ADC_V2_CHANNELS 10 | 74 | #define MAX_ADC_V2_CHANNELS 10 |
79 | #define MAX_ADC_V1_CHANNELS 8 | 75 | #define MAX_ADC_V1_CHANNELS 8 |
76 | #define MAX_EXYNOS3250_ADC_CHANNELS 2 | ||
80 | 77 | ||
81 | /* Bit definitions common for ADC_V1 and ADC_V2 */ | 78 | /* Bit definitions common for ADC_V1 and ADC_V2 */ |
82 | #define ADC_CON_EN_START (1u << 0) | 79 | #define ADC_CON_EN_START (1u << 0) |
@@ -85,9 +82,12 @@ enum adc_version { | |||
85 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) | 82 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) |
86 | 83 | ||
87 | struct exynos_adc { | 84 | struct exynos_adc { |
85 | struct exynos_adc_data *data; | ||
86 | struct device *dev; | ||
88 | void __iomem *regs; | 87 | void __iomem *regs; |
89 | void __iomem *enable_reg; | 88 | void __iomem *enable_reg; |
90 | struct clk *clk; | 89 | struct clk *clk; |
90 | struct clk *sclk; | ||
91 | unsigned int irq; | 91 | unsigned int irq; |
92 | struct regulator *vdd; | 92 | struct regulator *vdd; |
93 | 93 | ||
@@ -97,43 +97,213 @@ struct exynos_adc { | |||
97 | unsigned int version; | 97 | unsigned int version; |
98 | }; | 98 | }; |
99 | 99 | ||
100 | static const struct of_device_id exynos_adc_match[] = { | 100 | struct exynos_adc_data { |
101 | { .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 }, | 101 | int num_channels; |
102 | { .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 }, | 102 | bool needs_sclk; |
103 | {}, | 103 | |
104 | void (*init_hw)(struct exynos_adc *info); | ||
105 | void (*exit_hw)(struct exynos_adc *info); | ||
106 | void (*clear_irq)(struct exynos_adc *info); | ||
107 | void (*start_conv)(struct exynos_adc *info, unsigned long addr); | ||
104 | }; | 108 | }; |
105 | MODULE_DEVICE_TABLE(of, exynos_adc_match); | ||
106 | 109 | ||
107 | static inline unsigned int exynos_adc_get_version(struct platform_device *pdev) | 110 | static void exynos_adc_unprepare_clk(struct exynos_adc *info) |
108 | { | 111 | { |
109 | const struct of_device_id *match; | 112 | if (info->data->needs_sclk) |
113 | clk_unprepare(info->sclk); | ||
114 | clk_unprepare(info->clk); | ||
115 | } | ||
110 | 116 | ||
111 | match = of_match_node(exynos_adc_match, pdev->dev.of_node); | 117 | static int exynos_adc_prepare_clk(struct exynos_adc *info) |
112 | return (unsigned int)match->data; | 118 | { |
119 | int ret; | ||
120 | |||
121 | ret = clk_prepare(info->clk); | ||
122 | if (ret) { | ||
123 | dev_err(info->dev, "failed preparing adc clock: %d\n", ret); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | if (info->data->needs_sclk) { | ||
128 | ret = clk_prepare(info->sclk); | ||
129 | if (ret) { | ||
130 | clk_unprepare(info->clk); | ||
131 | dev_err(info->dev, | ||
132 | "failed preparing sclk_adc clock: %d\n", ret); | ||
133 | return ret; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static void exynos_adc_disable_clk(struct exynos_adc *info) | ||
141 | { | ||
142 | if (info->data->needs_sclk) | ||
143 | clk_disable(info->sclk); | ||
144 | clk_disable(info->clk); | ||
145 | } | ||
146 | |||
147 | static int exynos_adc_enable_clk(struct exynos_adc *info) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | ret = clk_enable(info->clk); | ||
152 | if (ret) { | ||
153 | dev_err(info->dev, "failed enabling adc clock: %d\n", ret); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | if (info->data->needs_sclk) { | ||
158 | ret = clk_enable(info->sclk); | ||
159 | if (ret) { | ||
160 | clk_disable(info->clk); | ||
161 | dev_err(info->dev, | ||
162 | "failed enabling sclk_adc clock: %d\n", ret); | ||
163 | return ret; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static void exynos_adc_v1_init_hw(struct exynos_adc *info) | ||
171 | { | ||
172 | u32 con1; | ||
173 | |||
174 | writel(1, info->enable_reg); | ||
175 | |||
176 | /* set default prescaler values and Enable prescaler */ | ||
177 | con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; | ||
178 | |||
179 | /* Enable 12-bit ADC resolution */ | ||
180 | con1 |= ADC_V1_CON_RES; | ||
181 | writel(con1, ADC_V1_CON(info->regs)); | ||
182 | } | ||
183 | |||
184 | static void exynos_adc_v1_exit_hw(struct exynos_adc *info) | ||
185 | { | ||
186 | u32 con; | ||
187 | |||
188 | writel(0, info->enable_reg); | ||
189 | |||
190 | con = readl(ADC_V1_CON(info->regs)); | ||
191 | con |= ADC_V1_CON_STANDBY; | ||
192 | writel(con, ADC_V1_CON(info->regs)); | ||
193 | } | ||
194 | |||
195 | static void exynos_adc_v1_clear_irq(struct exynos_adc *info) | ||
196 | { | ||
197 | writel(1, ADC_V1_INTCLR(info->regs)); | ||
198 | } | ||
199 | |||
200 | static void exynos_adc_v1_start_conv(struct exynos_adc *info, | ||
201 | unsigned long addr) | ||
202 | { | ||
203 | u32 con1; | ||
204 | |||
205 | writel(addr, ADC_V1_MUX(info->regs)); | ||
206 | |||
207 | con1 = readl(ADC_V1_CON(info->regs)); | ||
208 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | ||
209 | } | ||
210 | |||
211 | static const struct exynos_adc_data exynos_adc_v1_data = { | ||
212 | .num_channels = MAX_ADC_V1_CHANNELS, | ||
213 | |||
214 | .init_hw = exynos_adc_v1_init_hw, | ||
215 | .exit_hw = exynos_adc_v1_exit_hw, | ||
216 | .clear_irq = exynos_adc_v1_clear_irq, | ||
217 | .start_conv = exynos_adc_v1_start_conv, | ||
218 | }; | ||
219 | |||
220 | static void exynos_adc_v2_init_hw(struct exynos_adc *info) | ||
221 | { | ||
222 | u32 con1, con2; | ||
223 | |||
224 | writel(1, info->enable_reg); | ||
225 | |||
226 | con1 = ADC_V2_CON1_SOFT_RESET; | ||
227 | writel(con1, ADC_V2_CON1(info->regs)); | ||
228 | |||
229 | con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | | ||
230 | ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); | ||
231 | writel(con2, ADC_V2_CON2(info->regs)); | ||
232 | |||
233 | /* Enable interrupts */ | ||
234 | writel(1, ADC_V2_INT_EN(info->regs)); | ||
235 | } | ||
236 | |||
237 | static void exynos_adc_v2_exit_hw(struct exynos_adc *info) | ||
238 | { | ||
239 | u32 con; | ||
240 | |||
241 | writel(0, info->enable_reg); | ||
242 | |||
243 | con = readl(ADC_V2_CON1(info->regs)); | ||
244 | con &= ~ADC_CON_EN_START; | ||
245 | writel(con, ADC_V2_CON1(info->regs)); | ||
113 | } | 246 | } |
114 | 247 | ||
115 | static void exynos_adc_hw_init(struct exynos_adc *info) | 248 | static void exynos_adc_v2_clear_irq(struct exynos_adc *info) |
249 | { | ||
250 | writel(1, ADC_V2_INT_ST(info->regs)); | ||
251 | } | ||
252 | |||
253 | static void exynos_adc_v2_start_conv(struct exynos_adc *info, | ||
254 | unsigned long addr) | ||
116 | { | 255 | { |
117 | u32 con1, con2; | 256 | u32 con1, con2; |
118 | 257 | ||
119 | if (info->version == ADC_V2) { | 258 | con2 = readl(ADC_V2_CON2(info->regs)); |
120 | con1 = ADC_V2_CON1_SOFT_RESET; | 259 | con2 &= ~ADC_V2_CON2_ACH_MASK; |
121 | writel(con1, ADC_V2_CON1(info->regs)); | 260 | con2 |= ADC_V2_CON2_ACH_SEL(addr); |
261 | writel(con2, ADC_V2_CON2(info->regs)); | ||
122 | 262 | ||
123 | con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | | 263 | con1 = readl(ADC_V2_CON1(info->regs)); |
124 | ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); | 264 | writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs)); |
125 | writel(con2, ADC_V2_CON2(info->regs)); | 265 | } |
126 | 266 | ||
127 | /* Enable interrupts */ | 267 | static const struct exynos_adc_data exynos_adc_v2_data = { |
128 | writel(1, ADC_V2_INT_EN(info->regs)); | 268 | .num_channels = MAX_ADC_V2_CHANNELS, |
129 | } else { | ||
130 | /* set default prescaler values and Enable prescaler */ | ||
131 | con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; | ||
132 | 269 | ||
133 | /* Enable 12-bit ADC resolution */ | 270 | .init_hw = exynos_adc_v2_init_hw, |
134 | con1 |= ADC_V1_CON_RES; | 271 | .exit_hw = exynos_adc_v2_exit_hw, |
135 | writel(con1, ADC_V1_CON(info->regs)); | 272 | .clear_irq = exynos_adc_v2_clear_irq, |
136 | } | 273 | .start_conv = exynos_adc_v2_start_conv, |
274 | }; | ||
275 | |||
276 | static const struct exynos_adc_data exynos3250_adc_data = { | ||
277 | .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, | ||
278 | .needs_sclk = true, | ||
279 | |||
280 | .init_hw = exynos_adc_v2_init_hw, | ||
281 | .exit_hw = exynos_adc_v2_exit_hw, | ||
282 | .clear_irq = exynos_adc_v2_clear_irq, | ||
283 | .start_conv = exynos_adc_v2_start_conv, | ||
284 | }; | ||
285 | |||
286 | static const struct of_device_id exynos_adc_match[] = { | ||
287 | { | ||
288 | .compatible = "samsung,exynos-adc-v1", | ||
289 | .data = &exynos_adc_v1_data, | ||
290 | }, { | ||
291 | .compatible = "samsung,exynos-adc-v2", | ||
292 | .data = &exynos_adc_v2_data, | ||
293 | }, { | ||
294 | .compatible = "samsung,exynos3250-adc", | ||
295 | .data = &exynos3250_adc_data, | ||
296 | }, | ||
297 | {}, | ||
298 | }; | ||
299 | MODULE_DEVICE_TABLE(of, exynos_adc_match); | ||
300 | |||
301 | static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev) | ||
302 | { | ||
303 | const struct of_device_id *match; | ||
304 | |||
305 | match = of_match_node(exynos_adc_match, pdev->dev.of_node); | ||
306 | return (struct exynos_adc_data *)match->data; | ||
137 | } | 307 | } |
138 | 308 | ||
139 | static int exynos_read_raw(struct iio_dev *indio_dev, | 309 | static int exynos_read_raw(struct iio_dev *indio_dev, |
@@ -144,7 +314,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev, | |||
144 | { | 314 | { |
145 | struct exynos_adc *info = iio_priv(indio_dev); | 315 | struct exynos_adc *info = iio_priv(indio_dev); |
146 | unsigned long timeout; | 316 | unsigned long timeout; |
147 | u32 con1, con2; | ||
148 | int ret; | 317 | int ret; |
149 | 318 | ||
150 | if (mask != IIO_CHAN_INFO_RAW) | 319 | if (mask != IIO_CHAN_INFO_RAW) |
@@ -154,28 +323,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev, | |||
154 | reinit_completion(&info->completion); | 323 | reinit_completion(&info->completion); |
155 | 324 | ||
156 | /* Select the channel to be used and Trigger conversion */ | 325 | /* Select the channel to be used and Trigger conversion */ |
157 | if (info->version == ADC_V2) { | 326 | if (info->data->start_conv) |
158 | con2 = readl(ADC_V2_CON2(info->regs)); | 327 | info->data->start_conv(info, chan->address); |
159 | con2 &= ~ADC_V2_CON2_ACH_MASK; | ||
160 | con2 |= ADC_V2_CON2_ACH_SEL(chan->address); | ||
161 | writel(con2, ADC_V2_CON2(info->regs)); | ||
162 | |||
163 | con1 = readl(ADC_V2_CON1(info->regs)); | ||
164 | writel(con1 | ADC_CON_EN_START, | ||
165 | ADC_V2_CON1(info->regs)); | ||
166 | } else { | ||
167 | writel(chan->address, ADC_V1_MUX(info->regs)); | ||
168 | |||
169 | con1 = readl(ADC_V1_CON(info->regs)); | ||
170 | writel(con1 | ADC_CON_EN_START, | ||
171 | ADC_V1_CON(info->regs)); | ||
172 | } | ||
173 | 328 | ||
174 | timeout = wait_for_completion_timeout | 329 | timeout = wait_for_completion_timeout |
175 | (&info->completion, EXYNOS_ADC_TIMEOUT); | 330 | (&info->completion, EXYNOS_ADC_TIMEOUT); |
176 | if (timeout == 0) { | 331 | if (timeout == 0) { |
177 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); | 332 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); |
178 | exynos_adc_hw_init(info); | 333 | if (info->data->init_hw) |
334 | info->data->init_hw(info); | ||
179 | ret = -ETIMEDOUT; | 335 | ret = -ETIMEDOUT; |
180 | } else { | 336 | } else { |
181 | *val = info->value; | 337 | *val = info->value; |
@@ -193,13 +349,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id) | |||
193 | struct exynos_adc *info = (struct exynos_adc *)dev_id; | 349 | struct exynos_adc *info = (struct exynos_adc *)dev_id; |
194 | 350 | ||
195 | /* Read value */ | 351 | /* Read value */ |
196 | info->value = readl(ADC_V1_DATX(info->regs)) & | 352 | info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; |
197 | ADC_DATX_MASK; | 353 | |
198 | /* clear irq */ | 354 | /* clear irq */ |
199 | if (info->version == ADC_V2) | 355 | if (info->data->clear_irq) |
200 | writel(1, ADC_V2_INT_ST(info->regs)); | 356 | info->data->clear_irq(info); |
201 | else | ||
202 | writel(1, ADC_V1_INTCLR(info->regs)); | ||
203 | 357 | ||
204 | complete(&info->completion); | 358 | complete(&info->completion); |
205 | 359 | ||
@@ -277,6 +431,12 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
277 | 431 | ||
278 | info = iio_priv(indio_dev); | 432 | info = iio_priv(indio_dev); |
279 | 433 | ||
434 | info->data = exynos_adc_get_data(pdev); | ||
435 | if (!info->data) { | ||
436 | dev_err(&pdev->dev, "failed getting exynos_adc_data\n"); | ||
437 | return -EINVAL; | ||
438 | } | ||
439 | |||
280 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 440 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
281 | info->regs = devm_ioremap_resource(&pdev->dev, mem); | 441 | info->regs = devm_ioremap_resource(&pdev->dev, mem); |
282 | if (IS_ERR(info->regs)) | 442 | if (IS_ERR(info->regs)) |
@@ -294,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
294 | } | 454 | } |
295 | 455 | ||
296 | info->irq = irq; | 456 | info->irq = irq; |
457 | info->dev = &pdev->dev; | ||
297 | 458 | ||
298 | init_completion(&info->completion); | 459 | init_completion(&info->completion); |
299 | 460 | ||
@@ -304,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
304 | return PTR_ERR(info->clk); | 465 | return PTR_ERR(info->clk); |
305 | } | 466 | } |
306 | 467 | ||
468 | if (info->data->needs_sclk) { | ||
469 | info->sclk = devm_clk_get(&pdev->dev, "sclk"); | ||
470 | if (IS_ERR(info->sclk)) { | ||
471 | dev_err(&pdev->dev, | ||
472 | "failed getting sclk clock, err = %ld\n", | ||
473 | PTR_ERR(info->sclk)); | ||
474 | return PTR_ERR(info->sclk); | ||
475 | } | ||
476 | } | ||
477 | |||
307 | info->vdd = devm_regulator_get(&pdev->dev, "vdd"); | 478 | info->vdd = devm_regulator_get(&pdev->dev, "vdd"); |
308 | if (IS_ERR(info->vdd)) { | 479 | if (IS_ERR(info->vdd)) { |
309 | dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", | 480 | dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", |
@@ -315,13 +486,13 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
315 | if (ret) | 486 | if (ret) |
316 | return ret; | 487 | return ret; |
317 | 488 | ||
318 | ret = clk_prepare_enable(info->clk); | 489 | ret = exynos_adc_prepare_clk(info); |
319 | if (ret) | 490 | if (ret) |
320 | goto err_disable_reg; | 491 | goto err_disable_reg; |
321 | 492 | ||
322 | writel(1, info->enable_reg); | 493 | ret = exynos_adc_enable_clk(info); |
323 | 494 | if (ret) | |
324 | info->version = exynos_adc_get_version(pdev); | 495 | goto err_unprepare_clk; |
325 | 496 | ||
326 | platform_set_drvdata(pdev, indio_dev); | 497 | platform_set_drvdata(pdev, indio_dev); |
327 | 498 | ||
@@ -331,11 +502,7 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
331 | indio_dev->info = &exynos_adc_iio_info; | 502 | indio_dev->info = &exynos_adc_iio_info; |
332 | indio_dev->modes = INDIO_DIRECT_MODE; | 503 | indio_dev->modes = INDIO_DIRECT_MODE; |
333 | indio_dev->channels = exynos_adc_iio_channels; | 504 | indio_dev->channels = exynos_adc_iio_channels; |
334 | 505 | indio_dev->num_channels = info->data->num_channels; | |
335 | if (info->version == ADC_V1) | ||
336 | indio_dev->num_channels = MAX_ADC_V1_CHANNELS; | ||
337 | else | ||
338 | indio_dev->num_channels = MAX_ADC_V2_CHANNELS; | ||
339 | 506 | ||
340 | ret = request_irq(info->irq, exynos_adc_isr, | 507 | ret = request_irq(info->irq, exynos_adc_isr, |
341 | 0, dev_name(&pdev->dev), info); | 508 | 0, dev_name(&pdev->dev), info); |
@@ -349,7 +516,8 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
349 | if (ret) | 516 | if (ret) |
350 | goto err_irq; | 517 | goto err_irq; |
351 | 518 | ||
352 | exynos_adc_hw_init(info); | 519 | if (info->data->init_hw) |
520 | info->data->init_hw(info); | ||
353 | 521 | ||
354 | ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); | 522 | ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); |
355 | if (ret < 0) { | 523 | if (ret < 0) { |
@@ -366,8 +534,11 @@ err_of_populate: | |||
366 | err_irq: | 534 | err_irq: |
367 | free_irq(info->irq, info); | 535 | free_irq(info->irq, info); |
368 | err_disable_clk: | 536 | err_disable_clk: |
369 | writel(0, info->enable_reg); | 537 | if (info->data->exit_hw) |
370 | clk_disable_unprepare(info->clk); | 538 | info->data->exit_hw(info); |
539 | exynos_adc_disable_clk(info); | ||
540 | err_unprepare_clk: | ||
541 | exynos_adc_unprepare_clk(info); | ||
371 | err_disable_reg: | 542 | err_disable_reg: |
372 | regulator_disable(info->vdd); | 543 | regulator_disable(info->vdd); |
373 | return ret; | 544 | return ret; |
@@ -382,8 +553,10 @@ static int exynos_adc_remove(struct platform_device *pdev) | |||
382 | exynos_adc_remove_devices); | 553 | exynos_adc_remove_devices); |
383 | iio_device_unregister(indio_dev); | 554 | iio_device_unregister(indio_dev); |
384 | free_irq(info->irq, info); | 555 | free_irq(info->irq, info); |
385 | writel(0, info->enable_reg); | 556 | if (info->data->exit_hw) |
386 | clk_disable_unprepare(info->clk); | 557 | info->data->exit_hw(info); |
558 | exynos_adc_disable_clk(info); | ||
559 | exynos_adc_unprepare_clk(info); | ||
387 | regulator_disable(info->vdd); | 560 | regulator_disable(info->vdd); |
388 | 561 | ||
389 | return 0; | 562 | return 0; |
@@ -394,20 +567,10 @@ static int exynos_adc_suspend(struct device *dev) | |||
394 | { | 567 | { |
395 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 568 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
396 | struct exynos_adc *info = iio_priv(indio_dev); | 569 | struct exynos_adc *info = iio_priv(indio_dev); |
397 | u32 con; | ||
398 | 570 | ||
399 | if (info->version == ADC_V2) { | 571 | if (info->data->exit_hw) |
400 | con = readl(ADC_V2_CON1(info->regs)); | 572 | info->data->exit_hw(info); |
401 | con &= ~ADC_CON_EN_START; | 573 | exynos_adc_disable_clk(info); |
402 | writel(con, ADC_V2_CON1(info->regs)); | ||
403 | } else { | ||
404 | con = readl(ADC_V1_CON(info->regs)); | ||
405 | con |= ADC_V1_CON_STANDBY; | ||
406 | writel(con, ADC_V1_CON(info->regs)); | ||
407 | } | ||
408 | |||
409 | writel(0, info->enable_reg); | ||
410 | clk_disable_unprepare(info->clk); | ||
411 | regulator_disable(info->vdd); | 574 | regulator_disable(info->vdd); |
412 | 575 | ||
413 | return 0; | 576 | return 0; |
@@ -423,12 +586,12 @@ static int exynos_adc_resume(struct device *dev) | |||
423 | if (ret) | 586 | if (ret) |
424 | return ret; | 587 | return ret; |
425 | 588 | ||
426 | ret = clk_prepare_enable(info->clk); | 589 | ret = exynos_adc_enable_clk(info); |
427 | if (ret) | 590 | if (ret) |
428 | return ret; | 591 | return ret; |
429 | 592 | ||
430 | writel(1, info->enable_reg); | 593 | if (info->data->init_hw) |
431 | exynos_adc_hw_init(info); | 594 | info->data->init_hw(info); |
432 | 595 | ||
433 | return 0; | 596 | return 0; |
434 | } | 597 | } |