| .. | .. |
|---|
| 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); |
|---|