diff options
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r-- | drivers/iio/adc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/iio/adc/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/adc/ep93xx_adc.c | 6 | ||||
-rw-r--r-- | drivers/iio/adc/fsl-imx25-gcq.c | 17 | ||||
-rw-r--r-- | drivers/iio/adc/ingenic-adc.c | 102 | ||||
-rw-r--r-- | drivers/iio/adc/meson_saradc.c | 20 | ||||
-rw-r--r-- | drivers/iio/adc/palmas_gpadc.c | 4 | ||||
-rw-r--r-- | drivers/iio/adc/rn5t618-adc.c | 23 | ||||
-rw-r--r-- | drivers/iio/adc/rockchip_saradc.c | 69 | ||||
-rw-r--r-- | drivers/iio/adc/rzg2l_adc.c | 600 | ||||
-rw-r--r-- | drivers/iio/adc/ti-ads7950.c | 1 |
11 files changed, 814 insertions, 39 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index db0c8fb60515..af168e1c9fdb 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -887,6 +887,16 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +config RZG2L_ADC + tristate "Renesas RZ/G2L ADC driver" + depends on ARCH_R9A07G044 || COMPILE_TEST + help + Say yes here to build support for the ADC found in Renesas + RZ/G2L family. + + To compile this driver as a module, choose M here: the + module will be called rzg2l_adc. + config SC27XX_ADC tristate "Spreadtrum SC27xx series PMICs ADC" depends on MFD_SC27XX_PMIC || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index f70d877c555a..d68550f493e3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o +obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o obj-$(CONFIG_STX104) += stx104.o diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index a10a4e8d94fd..8edd6407b7c3 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -205,7 +205,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev) */ } - ret = clk_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(&pdev->dev, "Cannot enable clock\n"); return ret; @@ -213,7 +213,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev) ret = iio_device_register(iiodev); if (ret) - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -224,7 +224,7 @@ static int ep93xx_adc_remove(struct platform_device *pdev) struct ep93xx_adc_priv *priv = iio_priv(iiodev); iio_device_unregister(iiodev); - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); return 0; } diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index ab5139e911c3..329c555b55cc 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -201,11 +201,11 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, */ priv->vref[MX25_ADC_REFP_INT] = NULL; priv->vref[MX25_ADC_REFP_EXT] = - devm_regulator_get_optional(&pdev->dev, "vref-ext"); + devm_regulator_get_optional(dev, "vref-ext"); priv->vref[MX25_ADC_REFP_XP] = - devm_regulator_get_optional(&pdev->dev, "vref-xp"); + devm_regulator_get_optional(dev, "vref-xp"); priv->vref[MX25_ADC_REFP_YP] = - devm_regulator_get_optional(&pdev->dev, "vref-yp"); + devm_regulator_get_optional(dev, "vref-yp"); for_each_child_of_node(np, child) { u32 reg; @@ -307,7 +307,7 @@ static int mx25_gcq_probe(struct platform_device *pdev) int ret; int i; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; @@ -347,14 +347,11 @@ static int mx25_gcq_probe(struct platform_device *pdev) goto err_vref_disable; } - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq <= 0) { - ret = priv->irq; - if (!ret) - ret = -ENXIO; + ret = platform_get_irq(pdev, 0); + if (ret < 0) goto err_clk_unprepare; - } + priv->irq = ret; ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv); if (ret) { dev_err(dev, "Failed requesting IRQ\n"); diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 34c03a264f74..2b3912c6ca6b 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -37,6 +37,7 @@ #define JZ_ADC_REG_CFG_SAMPLE_NUM(n) ((n) << 10) #define JZ_ADC_REG_CFG_PULL_UP(n) ((n) << 16) #define JZ_ADC_REG_CFG_CMD_SEL BIT(22) +#define JZ_ADC_REG_CFG_VBAT_SEL BIT(30) #define JZ_ADC_REG_CFG_TOUCH_OPS_MASK (BIT(31) | GENMASK(23, 10)) #define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0 #define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16 @@ -71,6 +72,7 @@ #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10 #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986) #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12 +#define JZ4760_ADC_BATTERY_VREF 2500 #define JZ4770_ADC_BATTERY_VREF 1200 #define JZ4770_ADC_BATTERY_VREF_BITS 12 @@ -92,7 +94,7 @@ struct ingenic_adc_soc_data { const int *battery_scale_avail; size_t battery_scale_avail_size; unsigned int battery_vref_mode: 1; - unsigned int has_aux2: 1; + unsigned int has_aux_md: 1; const struct iio_chan_spec *channels; unsigned int num_channels; int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc); @@ -295,6 +297,10 @@ static const int jz4740_adc_battery_scale_avail[] = { JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS, }; +static const int jz4760_adc_battery_scale_avail[] = { + JZ4760_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS, +}; + static const int jz4770_adc_battery_raw_avail[] = { 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1, }; @@ -400,6 +406,47 @@ static const struct iio_chan_spec jz4740_channels[] = { }, }; +static const struct iio_chan_spec jz4760_channels[] = { + { + .extend_name = "aux", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX0, + .scan_index = -1, + }, + { + .extend_name = "aux1", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX, + .scan_index = -1, + }, + { + .extend_name = "aux2", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX2, + .scan_index = -1, + }, + { + .extend_name = "battery", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_BATTERY, + .scan_index = -1, + }, +}; + static const struct iio_chan_spec jz4770_channels[] = { { .type = IIO_VOLTAGE, @@ -506,7 +553,7 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = { .battery_scale_avail = jz4725b_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail), .battery_vref_mode = true, - .has_aux2 = false, + .has_aux_md = false, .channels = jz4740_channels, .num_channels = ARRAY_SIZE(jz4740_channels), .init_clk_div = jz4725b_adc_init_clk_div, @@ -520,12 +567,26 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = { .battery_scale_avail = jz4740_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail), .battery_vref_mode = true, - .has_aux2 = false, + .has_aux_md = false, .channels = jz4740_channels, .num_channels = ARRAY_SIZE(jz4740_channels), .init_clk_div = NULL, /* no ADCLK register on JZ4740 */ }; +static const struct ingenic_adc_soc_data jz4760_adc_soc_data = { + .battery_high_vref = JZ4760_ADC_BATTERY_VREF, + .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, + .battery_raw_avail = jz4770_adc_battery_raw_avail, + .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail), + .battery_scale_avail = jz4760_adc_battery_scale_avail, + .battery_scale_avail_size = ARRAY_SIZE(jz4760_adc_battery_scale_avail), + .battery_vref_mode = false, + .has_aux_md = true, + .channels = jz4760_channels, + .num_channels = ARRAY_SIZE(jz4760_channels), + .init_clk_div = jz4770_adc_init_clk_div, +}; + static const struct ingenic_adc_soc_data jz4770_adc_soc_data = { .battery_high_vref = JZ4770_ADC_BATTERY_VREF, .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, @@ -534,7 +595,7 @@ static const struct ingenic_adc_soc_data jz4770_adc_soc_data = { .battery_scale_avail = jz4770_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail), .battery_vref_mode = false, - .has_aux2 = true, + .has_aux_md = true, .channels = jz4770_channels, .num_channels = ARRAY_SIZE(jz4770_channels), .init_clk_div = jz4770_adc_init_clk_div, @@ -569,7 +630,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *chan, int *val) { - int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); + int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); struct ingenic_adc *adc = iio_priv(iio_dev); ret = clk_enable(adc->clk); @@ -579,11 +640,22 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, return ret; } - /* We cannot sample AUX/AUX2 in parallel. */ + /* We cannot sample the aux channels in parallel. */ mutex_lock(&adc->aux_lock); - if (adc->soc_data->has_aux2 && engine == 0) { - bit = BIT(chan->channel == INGENIC_ADC_AUX2); - ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit); + if (adc->soc_data->has_aux_md && engine == 0) { + switch (chan->channel) { + case INGENIC_ADC_AUX0: + cmd = 0; + break; + case INGENIC_ADC_AUX: + cmd = 1; + break; + case INGENIC_ADC_AUX2: + cmd = 2; + break; + } + + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, cmd); } ret = ingenic_adc_capture(adc, engine); @@ -591,6 +663,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, goto out; switch (chan->channel) { + case INGENIC_ADC_AUX0: case INGENIC_ADC_AUX: case INGENIC_ADC_AUX2: *val = readw(adc->base + JZ_ADC_REG_ADSDAT); @@ -621,6 +694,7 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev, return ingenic_adc_read_chan_info_raw(iio_dev, chan, val); case IIO_CHAN_INFO_SCALE: switch (chan->channel) { + case INGENIC_ADC_AUX0: case INGENIC_ADC_AUX: case INGENIC_ADC_AUX2: *val = JZ_ADC_AUX_VREF; @@ -806,6 +880,14 @@ static int ingenic_adc_probe(struct platform_device *pdev) /* Put hardware in a known passive state. */ writeb(0x00, adc->base + JZ_ADC_REG_ENABLE); writeb(0xff, adc->base + JZ_ADC_REG_CTRL); + + /* JZ4760B specific */ + if (device_property_present(dev, "ingenic,use-internal-divider")) + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, + JZ_ADC_REG_CFG_VBAT_SEL); + else + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, 0); + usleep_range(2000, 3000); /* Must wait at least 2ms. */ clk_disable(adc->clk); @@ -832,6 +914,8 @@ static int ingenic_adc_probe(struct platform_device *pdev) static const struct of_device_id ingenic_adc_of_match[] = { { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, }, { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, }, + { .compatible = "ingenic,jz4760-adc", .data = &jz4760_adc_soc_data, }, + { .compatible = "ingenic,jz4760b-adc", .data = &jz4760_adc_soc_data, }, { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, }, { }, }; diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 66dc452d643a..705d5e11a54b 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -347,7 +347,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, struct meson_sar_adc_priv *priv = iio_priv(indio_dev); int regval, fifo_chan, fifo_val, count; - if(!wait_for_completion_timeout(&priv->done, + if (!wait_for_completion_timeout(&priv->done, msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT))) return -ETIMEDOUT; @@ -497,8 +497,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) { /* prevent BL30 from using the SAR ADC while we are using it */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY); + MESON_SAR_ADC_DELAY_KERNEL_BUSY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); /* * wait until BL30 releases it's lock (so we can use the SAR @@ -525,7 +525,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) /* allow BL30 to use the SAR ADC again */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); mutex_unlock(&indio_dev->mlock); } @@ -791,7 +791,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) * on the vendor driver), which we don't support at the moment. */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0); + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0); /* disable all channels by default */ regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); @@ -1104,6 +1104,14 @@ static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { .resolution = 12, }; +static const struct meson_sar_adc_param meson_sar_adc_g12a_param = { + .has_bl30_integration = false, + .clock_rate = 1200000, + .bandgap_reg = MESON_SAR_ADC_REG11, + .regmap_config = &meson_sar_adc_regmap_config_gxbb, + .resolution = 12, +}; + static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { .param = &meson_sar_adc_meson8_param, .name = "meson-meson8-saradc", @@ -1140,7 +1148,7 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { }; static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { - .param = &meson_sar_adc_gxl_param, + .param = &meson_sar_adc_g12a_param, .name = "meson-g12a-saradc", }; diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 6ef09609be9f..f9c8385c72d3 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -664,8 +664,8 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) adc_period = adc->auto_conversion_period; for (i = 0; i < 16; ++i) { - if (((1000 * (1 << i)) / 32) < adc_period) - continue; + if (((1000 * (1 << i)) / 32) >= adc_period) + break; } if (i > 0) i--; diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index 7010c4276947..c56fccb2c8e1 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -16,6 +16,8 @@ #include <linux/completion.h> #include <linux/regmap.h> #include <linux/iio/iio.h> +#include <linux/iio/driver.h> +#include <linux/iio/machine.h> #include <linux/slab.h> #define RN5T618_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(500)) @@ -189,6 +191,19 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = { RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0") }; +static struct iio_map rn5t618_maps[] = { + IIO_MAP("VADP", "rn5t618-power", "vadp"), + IIO_MAP("VUSB", "rn5t618-power", "vusb"), + { /* sentinel */ } +}; + +static void unregister_map(void *data) +{ + struct iio_dev *iio_dev = (struct iio_dev *) data; + + iio_map_array_unregister(iio_dev); +} + static int rn5t618_adc_probe(struct platform_device *pdev) { int ret; @@ -239,6 +254,14 @@ static int rn5t618_adc_probe(struct platform_device *pdev) return ret; } + ret = iio_map_array_register(iio_dev, rn5t618_maps); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(adc->dev, unregister_map, iio_dev); + if (ret < 0) + return ret; + return devm_iio_device_register(adc->dev, iio_dev); } diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 12584f1631d8..a237fe469a30 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -35,7 +35,7 @@ #define SARADC_DLY_PU_SOC_MASK 0x3f #define SARADC_TIMEOUT msecs_to_jiffies(100) -#define SARADC_MAX_CHANNELS 6 +#define SARADC_MAX_CHANNELS 8 struct rockchip_saradc_data { const struct iio_chan_spec *channels; @@ -49,10 +49,12 @@ struct rockchip_saradc { struct clk *clk; struct completion completion; struct regulator *vref; + int uv_vref; struct reset_control *reset; const struct rockchip_saradc_data *data; u16 last_val; const struct iio_chan_spec *last_chan; + struct notifier_block nb; }; static void rockchip_saradc_power_down(struct rockchip_saradc *info) @@ -105,13 +107,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = regulator_get_voltage(info->vref); - if (ret < 0) { - dev_err(&indio_dev->dev, "failed to get voltage\n"); - return ret; - } - - *val = ret / 1000; + *val = info->uv_vref / 1000; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; default: @@ -192,6 +188,23 @@ static const struct rockchip_saradc_data rk3399_saradc_data = { .clk_rate = 1000000, }; +static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = { + SARADC_CHANNEL(0, "adc0", 10), + SARADC_CHANNEL(1, "adc1", 10), + SARADC_CHANNEL(2, "adc2", 10), + SARADC_CHANNEL(3, "adc3", 10), + SARADC_CHANNEL(4, "adc4", 10), + SARADC_CHANNEL(5, "adc5", 10), + SARADC_CHANNEL(6, "adc6", 10), + SARADC_CHANNEL(7, "adc7", 10), +}; + +static const struct rockchip_saradc_data rk3568_saradc_data = { + .channels = rockchip_rk3568_saradc_iio_channels, + .num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels), + .clk_rate = 1000000, +}; + static const struct of_device_id rockchip_saradc_match[] = { { .compatible = "rockchip,saradc", @@ -202,6 +215,9 @@ static const struct of_device_id rockchip_saradc_match[] = { }, { .compatible = "rockchip,rk3399-saradc", .data = &rk3399_saradc_data, + }, { + .compatible = "rockchip,rk3568-saradc", + .data = &rk3568_saradc_data, }, {}, }; @@ -278,6 +294,26 @@ out: return IRQ_HANDLED; } +static int rockchip_saradc_volt_notify(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct rockchip_saradc *info = + container_of(nb, struct rockchip_saradc, nb); + + if (event & REGULATOR_EVENT_VOLTAGE_CHANGE) + info->uv_vref = (unsigned long)data; + + return NOTIFY_OK; +} + +static void rockchip_saradc_regulator_unreg_notifier(void *data) +{ + struct rockchip_saradc *info = data; + + regulator_unregister_notifier(info->vref, &info->nb); +} + static int rockchip_saradc_probe(struct platform_device *pdev) { struct rockchip_saradc *info = NULL; @@ -390,6 +426,12 @@ static int rockchip_saradc_probe(struct platform_device *pdev) return ret; } + ret = regulator_get_voltage(info->vref); + if (ret < 0) + return ret; + + info->uv_vref = ret; + ret = clk_prepare_enable(info->pclk); if (ret < 0) { dev_err(&pdev->dev, "failed to enable pclk\n"); @@ -430,6 +472,17 @@ static int rockchip_saradc_probe(struct platform_device *pdev) if (ret) return ret; + info->nb.notifier_call = rockchip_saradc_volt_notify; + ret = regulator_register_notifier(info->vref, &info->nb); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&pdev->dev, + rockchip_saradc_regulator_unreg_notifier, + info); + if (ret) + return ret; + return devm_iio_device_register(&pdev->dev, indio_dev); } diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c new file mode 100644 index 000000000000..9996d5eef289 --- /dev/null +++ b/drivers/iio/adc/rzg2l_adc.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RZ/G2L A/D Converter driver + * + * Copyright (c) 2021 Renesas Electronics Europe GmbH + * + * Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#define DRIVER_NAME "rzg2l-adc" + +#define RZG2L_ADM(n) ((n) * 0x4) +#define RZG2L_ADM0_ADCE BIT(0) +#define RZG2L_ADM0_ADBSY BIT(1) +#define RZG2L_ADM0_PWDWNB BIT(2) +#define RZG2L_ADM0_SRESB BIT(15) +#define RZG2L_ADM1_TRG BIT(0) +#define RZG2L_ADM1_MS BIT(2) +#define RZG2L_ADM1_BS BIT(4) +#define RZG2L_ADM1_EGA_MASK GENMASK(13, 12) +#define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0) +#define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24) +#define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16) +#define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe) +#define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0) + +#define RZG2L_ADINT 0x20 +#define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0) +#define RZG2L_ADINT_CSEEN BIT(16) +#define RZG2L_ADINT_INTS BIT(31) + +#define RZG2L_ADSTS 0x24 +#define RZG2L_ADSTS_CSEST BIT(16) +#define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0) + +#define RZG2L_ADIVC 0x28 +#define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0) +#define RZG2L_ADIVC_DIVADC_4 FIELD_PREP(RZG2L_ADIVC_DIVADC_MASK, 0x4) + +#define RZG2L_ADFIL 0x2c + +#define RZG2L_ADCR(n) (0x30 + ((n) * 0x4)) +#define RZG2L_ADCR_AD_MASK GENMASK(11, 0) + +#define RZG2L_ADSMP_DEFUALT_SAMPLING 0x578 + +#define RZG2L_ADC_MAX_CHANNELS 8 +#define RZG2L_ADC_CHN_MASK 0x7 +#define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4) + +struct rzg2l_adc_data { + const struct iio_chan_spec *channels; + u8 num_channels; +}; + +struct rzg2l_adc { + void __iomem *base; + struct clk *pclk; + struct clk *adclk; + struct reset_control *presetn; + struct reset_control *adrstn; + struct completion completion; + const struct rzg2l_adc_data *data; + struct mutex lock; + u16 last_val[RZG2L_ADC_MAX_CHANNELS]; +}; + +static const char * const rzg2l_adc_channel_name[] = { + "adc0", + "adc1", + "adc2", + "adc3", + "adc4", + "adc5", + "adc6", + "adc7", +}; + +static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg) +{ + return readl(adc->base + reg); +} + +static void rzg2l_adc_writel(struct rzg2l_adc *adc, unsigned int reg, u32 val) +{ + writel(val, adc->base + reg); +} + +static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on) +{ + u32 reg; + + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + if (on) + reg |= RZG2L_ADM0_PWDWNB; + else + reg &= ~RZG2L_ADM0_PWDWNB; + rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); + udelay(2); +} + +static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start) +{ + int timeout = 5; + u32 reg; + + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + if (start) + reg |= RZG2L_ADM0_ADCE; + else + reg &= ~RZG2L_ADM0_ADCE; + rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); + + if (start) + return; + + do { + usleep_range(100, 200); + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + timeout--; + if (!timeout) { + pr_err("%s stopping ADC timed out\n", __func__); + break; + } + } while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE))); +} + +static void rzg2l_set_trigger(struct rzg2l_adc *adc) +{ + u32 reg; + + /* + * Setup ADM1 for SW trigger + * EGA[13:12] - Set 00 to indicate hardware trigger is invalid + * BS[4] - Enable 1-buffer mode + * MS[1] - Enable Select mode + * TRG[0] - Enable software trigger mode + */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(1)); + reg &= ~RZG2L_ADM1_EGA_MASK; + reg &= ~RZG2L_ADM1_BS; + reg &= ~RZG2L_ADM1_TRG; + reg |= RZG2L_ADM1_MS; + rzg2l_adc_writel(adc, RZG2L_ADM(1), reg); +} + +static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch) +{ + u32 reg; + + if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY) + return -EBUSY; + + rzg2l_set_trigger(adc); + + /* Select analog input channel subjected to conversion. */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(2)); + reg &= ~RZG2L_ADM2_CHSEL_MASK; + reg |= BIT(ch); + rzg2l_adc_writel(adc, RZG2L_ADM(2), reg); + + /* + * Setup ADINT + * INTS[31] - Select pulse signal + * CSEEN[16] - Enable channel select error interrupt + * INTEN[7:0] - Select channel interrupt + */ + reg = rzg2l_adc_readl(adc, RZG2L_ADINT); + reg &= ~RZG2L_ADINT_INTS; + reg &= ~RZG2L_ADINT_INTEN_MASK; + reg |= (RZG2L_ADINT_CSEEN | BIT(ch)); + rzg2l_adc_writel(adc, RZG2L_ADINT, reg); + + return 0; +} + +static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on) +{ + struct device *dev = indio_dev->dev.parent; + + if (on) + return pm_runtime_resume_and_get(dev); + + return pm_runtime_put_sync(dev); +} + +static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch) +{ + int ret; + + ret = rzg2l_adc_set_power(indio_dev, true); + if (ret) + return ret; + + ret = rzg2l_adc_conversion_setup(adc, ch); + if (ret) { + rzg2l_adc_set_power(indio_dev, false); + return ret; + } + + reinit_completion(&adc->completion); + + rzg2l_adc_start_stop(adc, true); + + if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) { + rzg2l_adc_writel(adc, RZG2L_ADINT, + rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK); + rzg2l_adc_start_stop(adc, false); + rzg2l_adc_set_power(indio_dev, false); + return -ETIMEDOUT; + } + + return rzg2l_adc_set_power(indio_dev, false); +} + +static int rzg2l_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rzg2l_adc *adc = iio_priv(indio_dev); + int ret; + u8 ch; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_VOLTAGE) + return -EINVAL; + + mutex_lock(&adc->lock); + ch = chan->channel & RZG2L_ADC_CHN_MASK; + ret = rzg2l_adc_conversion(indio_dev, adc, ch); + if (ret) { + mutex_unlock(&adc->lock); + return ret; + } + *val = adc->last_val[ch]; + mutex_unlock(&adc->lock); + + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int rzg2l_adc_read_label(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + char *label) +{ + if (chan->channel >= RZG2L_ADC_MAX_CHANNELS) + return -EINVAL; + + return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]); +} + +static const struct iio_info rzg2l_adc_iio_info = { + .read_raw = rzg2l_adc_read_raw, + .read_label = rzg2l_adc_read_label, +}; + +static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) +{ + struct rzg2l_adc *adc = dev_id; + unsigned long intst; + u32 reg; + int ch; + + reg = rzg2l_adc_readl(adc, RZG2L_ADSTS); + + /* A/D conversion channel select error interrupt */ + if (reg & RZG2L_ADSTS_CSEST) { + rzg2l_adc_writel(adc, RZG2L_ADSTS, reg); + return IRQ_HANDLED; + } + + intst = reg & RZG2L_ADSTS_INTST_MASK; + if (!intst) + return IRQ_NONE; + + for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS) + adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK; + + /* clear the channel interrupt */ + rzg2l_adc_writel(adc, RZG2L_ADSTS, reg); + + complete(&adc->completion); + + return IRQ_HANDLED; +} + +static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc) +{ + struct iio_chan_spec *chan_array; + struct fwnode_handle *fwnode; + struct rzg2l_adc_data *data; + unsigned int channel; + int num_channels; + int ret; + u8 i; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + num_channels = device_get_child_node_count(&pdev->dev); + if (!num_channels) { + dev_err(&pdev->dev, "no channel children\n"); + return -ENODEV; + } + + if (num_channels > RZG2L_ADC_MAX_CHANNELS) { + dev_err(&pdev->dev, "num of channel children out of range\n"); + return -EINVAL; + } + + chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array), + GFP_KERNEL); + if (!chan_array) + return -ENOMEM; + + i = 0; + device_for_each_child_node(&pdev->dev, fwnode) { + ret = fwnode_property_read_u32(fwnode, "reg", &channel); + if (ret) + return ret; + + if (channel >= RZG2L_ADC_MAX_CHANNELS) + return -EINVAL; + + chan_array[i].type = IIO_VOLTAGE; + chan_array[i].indexed = 1; + chan_array[i].channel = channel; + chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel]; + i++; + } + + data->num_channels = num_channels; + data->channels = chan_array; + adc->data = data; + + return 0; +} + +static int rzg2l_adc_hw_init(struct rzg2l_adc *adc) +{ + int timeout = 5; + u32 reg; + int ret; + + ret = clk_prepare_enable(adc->pclk); + if (ret) + return ret; + + /* SW reset */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + reg |= RZG2L_ADM0_SRESB; + rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); + + while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) { + if (!timeout) { + ret = -EBUSY; + goto exit_hw_init; + } + timeout--; + usleep_range(100, 200); + } + + /* Only division by 4 can be set */ + reg = rzg2l_adc_readl(adc, RZG2L_ADIVC); + reg &= ~RZG2L_ADIVC_DIVADC_MASK; + reg |= RZG2L_ADIVC_DIVADC_4; + rzg2l_adc_writel(adc, RZG2L_ADIVC, reg); + + /* + * Setup AMD3 + * ADIL[31:24] - Should be always set to 0 + * ADCMP[23:16] - Should be always set to 0xe + * ADSMP[15:0] - Set default (0x578) sampling period + */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(3)); + reg &= ~RZG2L_ADM3_ADIL_MASK; + reg &= ~RZG2L_ADM3_ADCMP_MASK; + reg &= ~RZG2L_ADM3_ADSMP_MASK; + reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFUALT_SAMPLING); + rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); + +exit_hw_init: + clk_disable_unprepare(adc->pclk); + + return 0; +} + +static void rzg2l_adc_pm_runtime_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_disable(dev->parent); +} + +static void rzg2l_adc_pm_runtime_set_suspended(void *data) +{ + struct device *dev = data; + + pm_runtime_set_suspended(dev->parent); +} + +static void rzg2l_adc_reset_assert(void *data) +{ + reset_control_assert(data); +} + +static int rzg2l_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct rzg2l_adc *adc; + int ret; + int irq; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + + ret = rzg2l_adc_parse_properties(pdev, adc); + if (ret) + return ret; + + mutex_init(&adc->lock); + + adc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adc->base)) + return PTR_ERR(adc->base); + + adc->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(adc->pclk)) { + dev_err(dev, "Failed to get pclk"); + return PTR_ERR(adc->pclk); + } + + adc->adclk = devm_clk_get(dev, "adclk"); + if (IS_ERR(adc->adclk)) { + dev_err(dev, "Failed to get adclk"); + return PTR_ERR(adc->adclk); + } + + adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n"); + if (IS_ERR(adc->adrstn)) { + dev_err(dev, "failed to get adrstn\n"); + return PTR_ERR(adc->adrstn); + } + + adc->presetn = devm_reset_control_get_exclusive(dev, "presetn"); + if (IS_ERR(adc->presetn)) { + dev_err(dev, "failed to get presetn\n"); + return PTR_ERR(adc->presetn); + } + + ret = reset_control_deassert(adc->adrstn); + if (ret) { + dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_reset_assert, adc->adrstn); + if (ret) { + dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n", + ret); + return ret; + } + + ret = reset_control_deassert(adc->presetn); + if (ret) { + dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_reset_assert, adc->presetn); + if (ret) { + dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n", + ret); + return ret; + } + + ret = rzg2l_adc_hw_init(adc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq resource\n"); + return irq; + } + + ret = devm_request_irq(dev, irq, rzg2l_adc_isr, + 0, dev_name(dev), adc); + if (ret < 0) + return ret; + + init_completion(&adc->completion); + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = DRIVER_NAME; + indio_dev->info = &rzg2l_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc->data->channels; + indio_dev->num_channels = adc->data->num_channels; + + pm_runtime_set_suspended(dev); + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev); + if (ret) + return ret; + + pm_runtime_enable(dev); + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_pm_runtime_disable, &indio_dev->dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id rzg2l_adc_match[] = { + { .compatible = "renesas,rzg2l-adc",}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rzg2l_adc_match); + +static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rzg2l_adc *adc = iio_priv(indio_dev); + + rzg2l_adc_pwr(adc, false); + clk_disable_unprepare(adc->adclk); + clk_disable_unprepare(adc->pclk); + + return 0; +} + +static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rzg2l_adc *adc = iio_priv(indio_dev); + int ret; + + ret = clk_prepare_enable(adc->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(adc->adclk); + if (ret) + return ret; + + rzg2l_adc_pwr(adc, true); + + return 0; +} + +static const struct dev_pm_ops rzg2l_adc_pm_ops = { + SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, + rzg2l_adc_pm_runtime_resume, + NULL) +}; + +static struct platform_driver rzg2l_adc_driver = { + .probe = rzg2l_adc_probe, + .driver = { + .name = DRIVER_NAME, + .of_match_table = rzg2l_adc_match, + .pm = &rzg2l_adc_pm_ops, + }, +}; + +module_platform_driver(rzg2l_adc_driver); + +MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); +MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 2383eacada87..a2b83f0bd526 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -568,7 +568,6 @@ static int ti_ads7950_probe(struct spi_device *spi) st->ring_xfer.tx_buf = &st->tx_buf[0]; st->ring_xfer.rx_buf = &st->rx_buf[0]; /* len will be set later */ - st->ring_xfer.cs_change = true; spi_message_add_tail(&st->ring_xfer, &st->ring_msg); |