// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #define RT9490_REG_ADCCTRL 0x2E #define RT9490_REG_ADCCHAN0 0x2F #define RT9490_REG_IBUSADC 0x31 #define RT9490_REG_IBATADC 0x33 #define RT9490_REG_VBUSADC 0x35 #define RT9490_REG_VAC1ADC 0x37 #define RT9490_REG_VAC2ADC 0x39 #define RT9490_REG_VBATADC 0x3B #define RT9490_REG_VSYSADC 0x3D #define RT9490_REG_TSADC 0x3F #define RT9490_REG_TDIEADC 0x41 #define RT9490_REG_DPADC 0x43 #define RT9490_REG_DMADC 0x45 #define RT9490_ADCDONE_MASK BIT(7) #define RT9490_ONESHOT_ENVAL (BIT(7) | BIT(6)) #define RT9490_ADCCONV_TIMEUS 5860 #define RT9490_ADC_SIGN_BIT BIT(15) struct rt9490_adc_data { struct device *dev; struct regmap *regmap; struct mutex lock; }; static int rt9490_read_channel(struct rt9490_adc_data *data, const struct iio_chan_spec *chan, int *val) { __le16 chan_enable; __be16 chan_raw_data; unsigned int status; u16 tmp; int ret; mutex_lock(&data->lock); ret = regmap_write(data->regmap, RT9490_REG_ADCCTRL, 0); if (ret) goto out_read; chan_enable = cpu_to_le16(~BIT(chan->scan_index)); ret = regmap_raw_write(data->regmap, RT9490_REG_ADCCHAN0, &chan_enable, sizeof(chan_enable)); if (ret) goto out_read; ret = regmap_write(data->regmap, RT9490_REG_ADCCTRL, RT9490_ONESHOT_ENVAL); if (ret) goto out_read; usleep_range(RT9490_ADCCONV_TIMEUS, RT9490_ADCCONV_TIMEUS + 1000); ret = regmap_read_poll_timeout(data->regmap, RT9490_REG_ADCCTRL, status, !(status & RT9490_ADCDONE_MASK), 100, RT9490_ADCCONV_TIMEUS); if (ret) { dev_err(data->dev, "adc read done flag [%d]\n", ret); goto out_read; } ret = regmap_raw_read(data->regmap, chan->address, &chan_raw_data, sizeof(chan_raw_data)); if (ret) { dev_err(data->dev, "Failed to read channel raw data\n"); goto out_read; } tmp = be16_to_cpu(chan_raw_data); if (tmp & RT9490_ADC_SIGN_BIT) { tmp &= ~RT9490_ADC_SIGN_BIT; *val = (s16)(~tmp + 1); } else *val = tmp; ret = IIO_VAL_INT; out_read: mutex_unlock(&data->lock); return ret; } static int rt9490_adc_read_raw(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long mask) { struct rt9490_adc_data *data = iio_priv(iio_dev); return rt9490_read_channel(data, chan, val); } static const struct iio_info rt9490_adc_info = { .read_raw = rt9490_adc_read_raw, }; #define RT9490_ADC_CHANNEL(_ch_name, _sc_idx, _type) \ { \ .type = _type, \ .channel = RT9490_CHAN_##_ch_name, \ .datasheet_name = #_ch_name, \ .address = RT9490_REG_##_ch_name##ADC, \ .scan_index = _sc_idx, \ .indexed = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ } static const struct iio_chan_spec rt9490_adc_channels[] = { RT9490_ADC_CHANNEL(TDIE, 1, IIO_TEMP), RT9490_ADC_CHANNEL(TS, 2, IIO_VOLTAGE), RT9490_ADC_CHANNEL(VSYS, 3, IIO_VOLTAGE), RT9490_ADC_CHANNEL(VBAT, 4, IIO_VOLTAGE), RT9490_ADC_CHANNEL(VBUS, 5, IIO_VOLTAGE), RT9490_ADC_CHANNEL(IBAT, 6, IIO_CURRENT), RT9490_ADC_CHANNEL(IBUS, 7, IIO_CURRENT), RT9490_ADC_CHANNEL(VAC1, 12, IIO_VOLTAGE), RT9490_ADC_CHANNEL(VAC2, 13, IIO_VOLTAGE), RT9490_ADC_CHANNEL(DM, 14, IIO_VOLTAGE), RT9490_ADC_CHANNEL(DP, 15, IIO_VOLTAGE) }; static int rt9490_adc_reset(struct rt9490_adc_data *data) { /* For each chan, 0 is enable, 1 is disable */ __le16 chan_enable = 0xffff; int ret; /* ADCEN = 0 */ ret = regmap_write(data->regmap, RT9490_REG_ADCCTRL, 0); if (ret) return ret; /* All channel EN to disable */ return regmap_raw_write(data->regmap, RT9490_REG_ADCCHAN0, &chan_enable, sizeof(chan_enable)); } static int rt9490_adc_probe(struct platform_device *pdev) { struct rt9490_adc_data *data; struct iio_dev *iio_dev; int ret; iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); if (!iio_dev) { dev_err(&pdev->dev, "Failed to allocate iio device\n"); return -ENOMEM; } data = iio_priv(iio_dev); if (!data) { dev_err(&pdev->dev, "Failed to get iio data\n"); return -ENODATA; } data->dev = &pdev->dev; mutex_init(&data->lock); data->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!data->regmap) { dev_err(&pdev->dev, "Failed to get parent regmap\n"); return -ENODEV; } ret = rt9490_adc_reset(data); if (ret) { dev_err(&pdev->dev, "Failed to reset adc hardware\n"); return ret; } iio_dev->name = dev_name(&pdev->dev); iio_dev->info = &rt9490_adc_info; iio_dev->modes = INDIO_DIRECT_MODE; iio_dev->channels = rt9490_adc_channels; iio_dev->num_channels = ARRAY_SIZE(rt9490_adc_channels); return devm_iio_device_register(&pdev->dev, iio_dev); } static const struct of_device_id rt9490_adc_of_match_table[] = { { .compatible = "richtek,rt9490-adc", }, { } }; MODULE_DEVICE_TABLE(of, rt9490_adc_of_match_table); static struct platform_driver rt9490_adc_driver = { .driver = { .name = "rt9490-adc", .of_match_table = rt9490_adc_of_match_table, }, .probe = rt9490_adc_probe, }; module_platform_driver(rt9490_adc_driver); MODULE_DESCRIPTION("Richtek RT9490 ADC driver"); MODULE_AUTHOR("ChiYuan Huang "); MODULE_LICENSE("GPL");