.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2016 MediaTek Inc. |
---|
3 | 4 | * Author: Zhiyong Tao <zhiyong.tao@mediatek.com> |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License version 2 as |
---|
7 | | - * published by the Free Software Foundation. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope that it will be useful, |
---|
10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | | - * GNU General Public License for more details. |
---|
13 | 5 | */ |
---|
14 | 6 | |
---|
15 | 7 | #include <linux/clk.h> |
---|
.. | .. |
---|
17 | 9 | #include <linux/err.h> |
---|
18 | 10 | #include <linux/kernel.h> |
---|
19 | 11 | #include <linux/module.h> |
---|
20 | | -#include <linux/of.h> |
---|
21 | | -#include <linux/of_device.h> |
---|
| 12 | +#include <linux/mod_devicetable.h> |
---|
22 | 13 | #include <linux/platform_device.h> |
---|
| 14 | +#include <linux/property.h> |
---|
23 | 15 | #include <linux/iopoll.h> |
---|
24 | 16 | #include <linux/io.h> |
---|
25 | 17 | #include <linux/iio/iio.h> |
---|
.. | .. |
---|
42 | 34 | #define MT6577_AUXADC_POWER_READY_MS 1 |
---|
43 | 35 | #define MT6577_AUXADC_SAMPLE_READY_US 25 |
---|
44 | 36 | |
---|
| 37 | +struct mtk_auxadc_compatible { |
---|
| 38 | + bool sample_data_cali; |
---|
| 39 | + bool check_global_idle; |
---|
| 40 | +}; |
---|
| 41 | + |
---|
45 | 42 | struct mt6577_auxadc_device { |
---|
46 | 43 | void __iomem *reg_base; |
---|
47 | 44 | struct clk *adc_clk; |
---|
48 | 45 | struct mutex lock; |
---|
| 46 | + const struct mtk_auxadc_compatible *dev_comp; |
---|
| 47 | +}; |
---|
| 48 | + |
---|
| 49 | +static const struct mtk_auxadc_compatible mt8173_compat = { |
---|
| 50 | + .sample_data_cali = false, |
---|
| 51 | + .check_global_idle = true, |
---|
| 52 | +}; |
---|
| 53 | + |
---|
| 54 | +static const struct mtk_auxadc_compatible mt6765_compat = { |
---|
| 55 | + .sample_data_cali = true, |
---|
| 56 | + .check_global_idle = false, |
---|
49 | 57 | }; |
---|
50 | 58 | |
---|
51 | 59 | #define MT6577_AUXADC_CHANNEL(idx) { \ |
---|
.. | .. |
---|
73 | 81 | MT6577_AUXADC_CHANNEL(14), |
---|
74 | 82 | MT6577_AUXADC_CHANNEL(15), |
---|
75 | 83 | }; |
---|
| 84 | + |
---|
| 85 | +/* For Voltage calculation */ |
---|
| 86 | +#define VOLTAGE_FULL_RANGE 1500 /* VA voltage */ |
---|
| 87 | +#define AUXADC_PRECISE 4096 /* 12 bits */ |
---|
| 88 | + |
---|
| 89 | +static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali) |
---|
| 90 | +{ |
---|
| 91 | + return rawdata; |
---|
| 92 | +} |
---|
76 | 93 | |
---|
77 | 94 | static inline void mt6577_auxadc_mod_reg(void __iomem *reg, |
---|
78 | 95 | u32 or_mask, u32 and_mask) |
---|
.. | .. |
---|
120 | 137 | /* we must delay here for hardware sample channel data */ |
---|
121 | 138 | udelay(MT6577_AUXADC_SAMPLE_READY_US); |
---|
122 | 139 | |
---|
123 | | - /* check MTK_AUXADC_CON2 if auxadc is idle */ |
---|
124 | | - ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val, |
---|
125 | | - ((val & MT6577_AUXADC_STA) == 0), |
---|
126 | | - MT6577_AUXADC_SLEEP_US, |
---|
127 | | - MT6577_AUXADC_TIMEOUT_US); |
---|
128 | | - if (ret < 0) { |
---|
129 | | - dev_err(indio_dev->dev.parent, |
---|
130 | | - "wait for auxadc idle time out\n"); |
---|
131 | | - goto err_timeout; |
---|
| 140 | + if (adc_dev->dev_comp->check_global_idle) { |
---|
| 141 | + /* check MTK_AUXADC_CON2 if auxadc is idle */ |
---|
| 142 | + ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, |
---|
| 143 | + val, ((val & MT6577_AUXADC_STA) == 0), |
---|
| 144 | + MT6577_AUXADC_SLEEP_US, |
---|
| 145 | + MT6577_AUXADC_TIMEOUT_US); |
---|
| 146 | + if (ret < 0) { |
---|
| 147 | + dev_err(indio_dev->dev.parent, |
---|
| 148 | + "wait for auxadc idle time out\n"); |
---|
| 149 | + goto err_timeout; |
---|
| 150 | + } |
---|
132 | 151 | } |
---|
133 | 152 | |
---|
134 | 153 | /* read channel and make sure ready bit == 1 */ |
---|
.. | .. |
---|
163 | 182 | int *val2, |
---|
164 | 183 | long info) |
---|
165 | 184 | { |
---|
| 185 | + struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev); |
---|
| 186 | + |
---|
166 | 187 | switch (info) { |
---|
167 | 188 | case IIO_CHAN_INFO_PROCESSED: |
---|
168 | 189 | *val = mt6577_auxadc_read(indio_dev, chan); |
---|
.. | .. |
---|
172 | 193 | chan->channel); |
---|
173 | 194 | return *val; |
---|
174 | 195 | } |
---|
| 196 | + if (adc_dev->dev_comp->sample_data_cali) |
---|
| 197 | + *val = mt_auxadc_get_cali_data(*val, true); |
---|
| 198 | + |
---|
| 199 | + /* Convert adc raw data to voltage: 0 - 1500 mV */ |
---|
| 200 | + *val = *val * VOLTAGE_FULL_RANGE / AUXADC_PRECISE; |
---|
| 201 | + |
---|
175 | 202 | return IIO_VAL_INT; |
---|
176 | 203 | |
---|
177 | 204 | default: |
---|
.. | .. |
---|
218 | 245 | { |
---|
219 | 246 | struct mt6577_auxadc_device *adc_dev; |
---|
220 | 247 | unsigned long adc_clk_rate; |
---|
221 | | - struct resource *res; |
---|
222 | 248 | struct iio_dev *indio_dev; |
---|
223 | 249 | int ret; |
---|
224 | 250 | |
---|
.. | .. |
---|
227 | 253 | return -ENOMEM; |
---|
228 | 254 | |
---|
229 | 255 | adc_dev = iio_priv(indio_dev); |
---|
230 | | - indio_dev->dev.parent = &pdev->dev; |
---|
231 | 256 | indio_dev->name = dev_name(&pdev->dev); |
---|
232 | 257 | indio_dev->info = &mt6577_auxadc_info; |
---|
233 | 258 | indio_dev->modes = INDIO_DIRECT_MODE; |
---|
234 | 259 | indio_dev->channels = mt6577_auxadc_iio_channels; |
---|
235 | 260 | indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels); |
---|
236 | 261 | |
---|
237 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
238 | | - adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res); |
---|
| 262 | + adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0); |
---|
239 | 263 | if (IS_ERR(adc_dev->reg_base)) { |
---|
240 | 264 | dev_err(&pdev->dev, "failed to get auxadc base address\n"); |
---|
241 | 265 | return PTR_ERR(adc_dev->reg_base); |
---|
.. | .. |
---|
259 | 283 | dev_err(&pdev->dev, "null clock rate\n"); |
---|
260 | 284 | goto err_disable_clk; |
---|
261 | 285 | } |
---|
| 286 | + |
---|
| 287 | + adc_dev->dev_comp = device_get_match_data(&pdev->dev); |
---|
262 | 288 | |
---|
263 | 289 | mutex_init(&adc_dev->lock); |
---|
264 | 290 | |
---|
.. | .. |
---|
304 | 330 | mt6577_auxadc_resume); |
---|
305 | 331 | |
---|
306 | 332 | static const struct of_device_id mt6577_auxadc_of_match[] = { |
---|
307 | | - { .compatible = "mediatek,mt2701-auxadc", }, |
---|
308 | | - { .compatible = "mediatek,mt2712-auxadc", }, |
---|
309 | | - { .compatible = "mediatek,mt7622-auxadc", }, |
---|
310 | | - { .compatible = "mediatek,mt8173-auxadc", }, |
---|
| 333 | + { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat}, |
---|
| 334 | + { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat}, |
---|
| 335 | + { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat}, |
---|
| 336 | + { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat}, |
---|
| 337 | + { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat}, |
---|
311 | 338 | { } |
---|
312 | 339 | }; |
---|
313 | 340 | MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match); |
---|