diff options
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 | } |