summaryrefslogtreecommitdiff
path: root/drivers/iio/adc/meson_saradc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/meson_saradc.c')
-rw-r--r--drivers/iio/adc/meson_saradc.c711
1 files changed, 450 insertions, 261 deletions
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 729becb2d3d9..47cd350498a0 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1,14 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Amlogic Meson Successive Approximation Register (SAR) A/D Converter
*
* Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/bitfield.h>
@@ -18,14 +12,15 @@
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/mfd/syscon.h>
#define MESON_SAR_ADC_REG0 0x00
#define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
@@ -76,7 +71,7 @@
#define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18)
#define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16)
#define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10
- #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5
+ #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 6
#define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8)
#define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0)
@@ -160,6 +155,15 @@
*/
#define MESON_SAR_ADC_REG11 0x2c
#define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13)
+ #define MESON_SAR_ADC_REG11_CMV_SEL BIT(6)
+ #define MESON_SAR_ADC_REG11_VREF_VOLTAGE BIT(5)
+ #define MESON_SAR_ADC_REG11_EOC BIT(1)
+ #define MESON_SAR_ADC_REG11_VREF_SEL BIT(0)
+
+#define MESON_SAR_ADC_REG12 0x30
+ #define MESON_SAR_ADC_REG12_MPLL0_UNKNOWN BIT(0)
+ #define MESON_SAR_ADC_REG12_MPLL1_UNKNOWN BIT(1)
+ #define MESON_SAR_ADC_REG12_MPLL2_UNKNOWN BIT(2)
#define MESON_SAR_ADC_REG13 0x34
#define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8)
@@ -167,6 +171,7 @@
#define MESON_SAR_ADC_MAX_FIFO_SIZE 32
#define MESON_SAR_ADC_TIMEOUT 100 /* ms */
#define MESON_SAR_ADC_VOLTAGE_AND_TEMP_CHANNEL 6
+#define MESON_SAR_ADC_VOLTAGE_AND_MUX_CHANNEL 7
#define MESON_SAR_ADC_TEMP_OFFSET 27
/* temperature sensor calibration information in eFuse */
@@ -174,6 +179,9 @@
#define MESON_SAR_ADC_EFUSE_BYTE3_UPPER_ADC_VAL GENMASK(6, 0)
#define MESON_SAR_ADC_EFUSE_BYTE3_IS_CALIBRATED BIT(7)
+#define MESON_HHI_DPLL_TOP_0 0x318
+#define MESON_HHI_DPLL_TOP_0_TSC_BIT4 BIT(9)
+
/* for use with IIO_VAL_INT_PLUS_MICRO */
#define MILLION 1000000
@@ -203,29 +211,22 @@
.datasheet_name = "TEMP_SENSOR", \
}
-static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
- MESON_SAR_ADC_CHAN(0),
- MESON_SAR_ADC_CHAN(1),
- MESON_SAR_ADC_CHAN(2),
- MESON_SAR_ADC_CHAN(3),
- MESON_SAR_ADC_CHAN(4),
- MESON_SAR_ADC_CHAN(5),
- MESON_SAR_ADC_CHAN(6),
- MESON_SAR_ADC_CHAN(7),
- IIO_CHAN_SOFT_TIMESTAMP(8),
-};
+#define MESON_SAR_ADC_MUX(_chan, _sel) { \
+ .type = IIO_VOLTAGE, \
+ .channel = _chan, \
+ .indexed = 1, \
+ .address = MESON_SAR_ADC_VOLTAGE_AND_MUX_CHANNEL, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_CALIBBIAS) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE), \
+ .datasheet_name = "SAR_ADC_MUX_"#_sel, \
+}
-static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = {
- MESON_SAR_ADC_CHAN(0),
- MESON_SAR_ADC_CHAN(1),
- MESON_SAR_ADC_CHAN(2),
- MESON_SAR_ADC_CHAN(3),
- MESON_SAR_ADC_CHAN(4),
- MESON_SAR_ADC_CHAN(5),
- MESON_SAR_ADC_CHAN(6),
- MESON_SAR_ADC_CHAN(7),
- MESON_SAR_ADC_TEMP_CHAN(8),
- IIO_CHAN_SOFT_TIMESTAMP(9),
+enum meson_sar_adc_vref_sel {
+ VREF_CALIBATION_VOLTAGE = 0,
+ VREF_VDDA = 1,
};
enum meson_sar_adc_avg_mode {
@@ -250,15 +251,87 @@ enum meson_sar_adc_chan7_mux_sel {
CHAN7_MUX_CH7_INPUT = 0x7,
};
+enum meson_sar_adc_channel_index {
+ NUM_CHAN_0,
+ NUM_CHAN_1,
+ NUM_CHAN_2,
+ NUM_CHAN_3,
+ NUM_CHAN_4,
+ NUM_CHAN_5,
+ NUM_CHAN_6,
+ NUM_CHAN_7,
+ NUM_CHAN_TEMP,
+ NUM_MUX_0_VSS,
+ NUM_MUX_1_VDD_DIV4,
+ NUM_MUX_2_VDD_DIV2,
+ NUM_MUX_3_VDD_MUL3_DIV4,
+ NUM_MUX_4_VDD,
+};
+
+static enum meson_sar_adc_chan7_mux_sel chan7_mux_values[] = {
+ CHAN7_MUX_VSS,
+ CHAN7_MUX_VDD_DIV4,
+ CHAN7_MUX_VDD_DIV2,
+ CHAN7_MUX_VDD_MUL3_DIV4,
+ CHAN7_MUX_VDD,
+};
+
+static const char * const chan7_mux_names[] = {
+ [CHAN7_MUX_VSS] = "gnd",
+ [CHAN7_MUX_VDD_DIV4] = "0.25vdd",
+ [CHAN7_MUX_VDD_DIV2] = "0.5vdd",
+ [CHAN7_MUX_VDD_MUL3_DIV4] = "0.75vdd",
+ [CHAN7_MUX_VDD] = "vdd",
+};
+
+static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
+ MESON_SAR_ADC_CHAN(NUM_CHAN_0),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_1),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_2),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_3),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_4),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_5),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_6),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_7),
+ MESON_SAR_ADC_MUX(NUM_MUX_0_VSS, 0),
+ MESON_SAR_ADC_MUX(NUM_MUX_1_VDD_DIV4, 1),
+ MESON_SAR_ADC_MUX(NUM_MUX_2_VDD_DIV2, 2),
+ MESON_SAR_ADC_MUX(NUM_MUX_3_VDD_MUL3_DIV4, 3),
+ MESON_SAR_ADC_MUX(NUM_MUX_4_VDD, 4),
+};
+
+static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = {
+ MESON_SAR_ADC_CHAN(NUM_CHAN_0),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_1),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_2),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_3),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_4),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_5),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_6),
+ MESON_SAR_ADC_CHAN(NUM_CHAN_7),
+ MESON_SAR_ADC_TEMP_CHAN(NUM_CHAN_TEMP),
+ MESON_SAR_ADC_MUX(NUM_MUX_0_VSS, 0),
+ MESON_SAR_ADC_MUX(NUM_MUX_1_VDD_DIV4, 1),
+ MESON_SAR_ADC_MUX(NUM_MUX_2_VDD_DIV2, 2),
+ MESON_SAR_ADC_MUX(NUM_MUX_3_VDD_MUL3_DIV4, 3),
+ MESON_SAR_ADC_MUX(NUM_MUX_4_VDD, 4),
+};
+
struct meson_sar_adc_param {
bool has_bl30_integration;
unsigned long clock_rate;
- u32 bandgap_reg;
unsigned int resolution;
const struct regmap_config *regmap_config;
u8 temperature_trimming_bits;
unsigned int temperature_multiplier;
unsigned int temperature_divider;
+ u8 disable_ring_counter;
+ bool has_vref_select;
+ u8 vref_select;
+ u8 cmv_select;
+ u8 adc_eoc;
+ enum meson_sar_adc_vref_sel vref_voltage;
+ bool enable_mpll_clock_workaround;
};
struct meson_sar_adc_data {
@@ -278,11 +351,15 @@ struct meson_sar_adc_priv {
struct clk *adc_div_clk;
struct clk_divider clk_div;
struct completion done;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
int calibbias;
int calibscale;
+ struct regmap *tsc_regmap;
bool temperature_sensor_calibrated;
u8 temperature_sensor_coefficient;
u16 temperature_sensor_adc_val;
+ enum meson_sar_adc_chan7_mux_sel chan7_mux_sel;
};
static const struct regmap_config meson_sar_adc_regmap_config_gxbb = {
@@ -299,6 +376,17 @@ static const struct regmap_config meson_sar_adc_regmap_config_meson8 = {
.max_register = MESON_SAR_ADC_DELTA_10,
};
+static const struct iio_chan_spec *
+find_channel_by_num(struct iio_dev *indio_dev, int num)
+{
+ int i;
+
+ for (i = 0; i < indio_dev->num_channels; i++)
+ if (indio_dev->channels[i].channel == num)
+ return &indio_dev->channels[i];
+ return NULL;
+}
+
static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
@@ -323,22 +411,32 @@ static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val)
static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- int regval, timeout = 10000;
+ int val;
/*
* NOTE: we need a small delay before reading the status, otherwise
* the sample engine may not have started internally (which would
* seem to us that sampling is already finished).
*/
- do {
- udelay(1);
- regmap_read(priv->regmap, MESON_SAR_ADC_REG0, &regval);
- } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
+ udelay(1);
+ return regmap_read_poll_timeout_atomic(priv->regmap, MESON_SAR_ADC_REG0, val,
+ !FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, val),
+ 1, 10000);
+}
- if (timeout < 0)
- return -ETIMEDOUT;
+static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev,
+ enum meson_sar_adc_chan7_mux_sel sel)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ u32 regval;
- return 0;
+ regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
+
+ usleep_range(10, 20);
+
+ priv->chan7_mux_sel = sel;
}
static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
@@ -346,24 +444,23 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
int *val)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
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;
count = meson_sar_adc_get_fifo_count(indio_dev);
if (count != 1) {
- dev_err(&indio_dev->dev,
- "ADC FIFO has %d element(s) instead of one\n", count);
+ dev_err(dev, "ADC FIFO has %d element(s) instead of one\n", count);
return -EINVAL;
}
regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &regval);
fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
if (fifo_chan != chan->address) {
- dev_err(&indio_dev->dev,
- "ADC FIFO entry belongs to channel %d instead of %lu\n",
+ dev_err(dev, "ADC FIFO entry belongs to channel %d instead of %lu\n",
fifo_chan, chan->address);
return -EINVAL;
}
@@ -435,20 +532,16 @@ static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
regmap_update_bits(priv->regmap,
MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TEMP_SEL, regval);
- }
-}
-
-static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev,
- enum meson_sar_adc_chan7_mux_sel sel)
-{
- struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- u32 regval;
+ } else if (chan->address == MESON_SAR_ADC_VOLTAGE_AND_MUX_CHANNEL) {
+ enum meson_sar_adc_chan7_mux_sel sel;
- regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
-
- usleep_range(10, 20);
+ if (chan->channel == NUM_CHAN_7)
+ sel = CHAN7_MUX_CH7_INPUT;
+ else
+ sel = chan7_mux_values[chan->channel - NUM_MUX_0_VSS];
+ if (sel != priv->chan7_mux_sel)
+ meson_sar_adc_set_chan7_mux(indio_dev, sel);
+ }
}
static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev)
@@ -457,62 +550,57 @@ static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev)
reinit_completion(&priv->done);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_FIFO_IRQ_EN,
- MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
- MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLING_START,
- MESON_SAR_ADC_REG0_SAMPLING_START);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_START);
}
static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLING_STOP,
- MESON_SAR_ADC_REG0_SAMPLING_STOP);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_STOP);
/* wait until all modules are stopped */
meson_sar_adc_wait_busy_clear(indio_dev);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
}
static int meson_sar_adc_lock(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- int val, timeout = 10000;
+ int val, ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&priv->lock);
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,
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
+ udelay(1);
+
/*
* wait until BL30 releases it's lock (so we can use the SAR
* ADC)
*/
- do {
- udelay(1);
- regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
- } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
-
- if (timeout < 0) {
- mutex_unlock(&indio_dev->mlock);
- return -ETIMEDOUT;
+ ret = regmap_read_poll_timeout_atomic(priv->regmap, MESON_SAR_ADC_DELAY, val,
+ !(val & MESON_SAR_ADC_DELAY_BL30_BUSY),
+ 1, 10000);
+ if (ret) {
+ mutex_unlock(&priv->lock);
+ return ret;
}
}
@@ -525,10 +613,10 @@ 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);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&priv->lock);
}
static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev)
@@ -551,6 +639,7 @@ static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
int *val)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
int ret;
if (chan->type == IIO_TEMP && !priv->temperature_sensor_calibrated)
@@ -574,8 +663,7 @@ static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
meson_sar_adc_unlock(indio_dev);
if (ret) {
- dev_warn(indio_dev->dev.parent,
- "failed to read sample for channel %lu: %d\n",
+ dev_warn(dev, "failed to read sample for channel %lu: %d\n",
chan->address, ret);
return ret;
}
@@ -588,27 +676,24 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING,
ONE_SAMPLE, val);
- break;
case IIO_CHAN_INFO_AVERAGE_RAW:
return meson_sar_adc_get_sample(indio_dev, chan,
MEAN_AVERAGING, EIGHT_SAMPLES,
val);
- break;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_VOLTAGE) {
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
- dev_err(indio_dev->dev.parent,
- "failed to get vref voltage: %d\n",
- ret);
+ dev_err(dev, "failed to get vref voltage: %d\n", ret);
return ret;
}
@@ -653,11 +738,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
void __iomem *base)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
struct clk_init_data init;
const char *clk_parents[1];
- init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
- dev_name(indio_dev->dev.parent));
+ init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#adc_div", dev_name(dev));
if (!init.name)
return -ENOMEM;
@@ -673,13 +758,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
priv->clk_div.hw.init = &init;
priv->clk_div.flags = 0;
- priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
- &priv->clk_div.hw);
+ priv->adc_div_clk = devm_clk_register(dev, &priv->clk_div.hw);
if (WARN_ON(IS_ERR(priv->adc_div_clk)))
return PTR_ERR(priv->adc_div_clk);
- init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
- dev_name(indio_dev->dev.parent));
+ init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#adc_en", dev_name(dev));
if (!init.name)
return -ENOMEM;
@@ -693,7 +776,7 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
priv->clk_gate.bit_idx = __ffs(MESON_SAR_ADC_REG3_CLK_EN);
priv->clk_gate.hw.init = &init;
- priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
+ priv->adc_clk = devm_clk_register(dev, &priv->clk_gate.hw);
if (WARN_ON(IS_ERR(priv->adc_clk)))
return PTR_ERR(priv->adc_clk);
@@ -704,12 +787,12 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
u8 *buf, trimming_bits, trimming_mask, upper_adc_val;
+ struct device *dev = indio_dev->dev.parent;
struct nvmem_cell *temperature_calib;
size_t read_len;
int ret;
- temperature_calib = devm_nvmem_cell_get(&indio_dev->dev,
- "temperature_calib");
+ temperature_calib = devm_nvmem_cell_get(dev, "temperature_calib");
if (IS_ERR(temperature_calib)) {
ret = PTR_ERR(temperature_calib);
@@ -720,24 +803,21 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
if (ret == -ENODEV)
return 0;
- if (ret != -EPROBE_DEFER)
- dev_err(indio_dev->dev.parent,
- "failed to get temperature_calib cell\n");
-
- return ret;
+ return dev_err_probe(dev, ret, "failed to get temperature_calib cell\n");
}
+ priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
+ if (IS_ERR(priv->tsc_regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
+ "failed to get amlogic,hhi-sysctrl regmap\n");
+
read_len = MESON_SAR_ADC_EFUSE_BYTES;
buf = nvmem_cell_read(temperature_calib, &read_len);
- if (IS_ERR(buf)) {
- dev_err(indio_dev->dev.parent,
- "failed to read temperature_calib cell\n");
- return PTR_ERR(buf);
- } else if (read_len != MESON_SAR_ADC_EFUSE_BYTES) {
+ if (IS_ERR(buf))
+ return dev_err_probe(dev, PTR_ERR(buf), "failed to read temperature_calib cell\n");
+ if (read_len != MESON_SAR_ADC_EFUSE_BYTES) {
kfree(buf);
- dev_err(indio_dev->dev.parent,
- "invalid read size of temperature_calib cell\n");
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL, "invalid read size of temperature_calib cell\n");
}
trimming_bits = priv->param->temperature_trimming_bits;
@@ -762,6 +842,7 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
static int meson_sar_adc_init(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
int regval, i, ret;
/*
@@ -787,17 +868,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
* disable this bit as seems to be only relevant for Meson6 (based
* 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);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
/* disable all channels by default */
regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY,
- MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
/* delay between two samples = (10+1) * 1uS */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
@@ -832,6 +912,18 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK,
regval);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW);
+
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW);
+
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW);
+
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW);
+
/*
* set up the input channel muxes in MESON_SAR_ADC_AUX_SW
* (2 = SAR_ADC_CH2, 3 = SAR_ADC_CH3, ...) and enable
@@ -846,12 +938,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval);
if (priv->temperature_sensor_calibrated) {
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE1,
- MESON_SAR_ADC_DELTA_10_TS_REVE1);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE0,
- MESON_SAR_ADC_DELTA_10_TS_REVE0);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE1);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE0);
/*
* set bits [3:0] of the TSC (temperature sensor coefficient)
@@ -861,26 +951,74 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
priv->temperature_sensor_coefficient);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_C_MASK, regval);
+
+ if (priv->param->temperature_trimming_bits == 5) {
+ if (priv->temperature_sensor_coefficient & BIT(4))
+ regval = MESON_HHI_DPLL_TOP_0_TSC_BIT4;
+ else
+ regval = 0;
+
+ /*
+ * bit [4] (the 5th bit when starting to count at 1)
+ * of the TSC is located in the HHI register area.
+ */
+ regmap_update_bits(priv->tsc_regmap,
+ MESON_HHI_DPLL_TOP_0,
+ MESON_HHI_DPLL_TOP_0_TSC_BIT4,
+ regval);
+ }
} else {
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE1, 0);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE0, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE1);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE0);
}
- ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
- if (ret) {
- dev_err(indio_dev->dev.parent,
- "failed to set adc parent to clkin\n");
- return ret;
+ regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
+ priv->param->disable_ring_counter);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
+ regval);
+
+ if (priv->param->regmap_config->max_register >= MESON_SAR_ADC_REG11) {
+ regval = FIELD_PREP(MESON_SAR_ADC_REG11_EOC, priv->param->adc_eoc);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_EOC, regval);
+
+ if (priv->param->has_vref_select) {
+ regval = FIELD_PREP(MESON_SAR_ADC_REG11_VREF_SEL,
+ priv->param->vref_select);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_VREF_SEL, regval);
+ }
+
+ regval = FIELD_PREP(MESON_SAR_ADC_REG11_VREF_VOLTAGE,
+ priv->param->vref_voltage);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_VREF_VOLTAGE, regval);
+
+ regval = FIELD_PREP(MESON_SAR_ADC_REG11_CMV_SEL,
+ priv->param->cmv_select);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_CMV_SEL, regval);
+
+ if (priv->param->enable_mpll_clock_workaround) {
+ dev_warn(dev,
+ "Enabling unknown bits to make the MPLL clocks work. This may change so always update dtbs and kernel together\n");
+ regmap_write(priv->regmap, MESON_SAR_ADC_REG12,
+ MESON_SAR_ADC_REG12_MPLL0_UNKNOWN |
+ MESON_SAR_ADC_REG12_MPLL1_UNKNOWN |
+ MESON_SAR_ADC_REG12_MPLL2_UNKNOWN);
+ }
}
+ ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set adc parent to clkin\n");
+
ret = clk_set_rate(priv->adc_clk, priv->param->clock_rate);
- if (ret) {
- dev_err(indio_dev->dev.parent,
- "failed to set adc clock rate\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set adc clock rate\n");
return 0;
}
@@ -888,56 +1026,50 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- const struct meson_sar_adc_param *param = priv->param;
- u32 enable_mask;
- if (param->bandgap_reg == MESON_SAR_ADC_REG11)
- enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN;
+ if (priv->param->regmap_config->max_register >= MESON_SAR_ADC_REG11)
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_BANDGAP_EN,
+ on_off ? MESON_SAR_ADC_REG11_BANDGAP_EN : 0);
else
- enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN;
-
- regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask,
- on_off ? enable_mask : 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_VBG_EN,
+ on_off ? MESON_SAR_ADC_DELTA_10_TS_VBG_EN : 0);
}
static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
int ret;
u32 regval;
ret = meson_sar_adc_lock(indio_dev);
- if (ret)
+ if (ret) {
+ dev_err(dev, "failed to lock adc\n");
goto err_lock;
+ }
ret = regulator_enable(priv->vref);
if (ret < 0) {
- dev_err(indio_dev->dev.parent,
- "failed to enable vref regulator\n");
+ dev_err(dev, "failed to enable vref regulator\n");
goto err_vref;
}
- ret = clk_prepare_enable(priv->core_clk);
- if (ret) {
- dev_err(indio_dev->dev.parent, "failed to enable core clk\n");
- goto err_core_clk;
- }
-
regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval);
meson_sar_adc_set_bandgap(indio_dev, true);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_ADC_EN,
- MESON_SAR_ADC_REG3_ADC_EN);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN);
udelay(5);
ret = clk_prepare_enable(priv->adc_clk);
if (ret) {
- dev_err(indio_dev->dev.parent, "failed to enable adc clk\n");
+ dev_err(dev, "failed to enable adc clk\n");
goto err_adc_clk;
}
@@ -946,11 +1078,9 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
return 0;
err_adc_clk:
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_ADC_EN, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN);
meson_sar_adc_set_bandgap(indio_dev, false);
- clk_disable_unprepare(priv->core_clk);
-err_core_clk:
regulator_disable(priv->vref);
err_vref:
meson_sar_adc_unlock(indio_dev);
@@ -958,29 +1088,30 @@ err_lock:
return ret;
}
-static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
+static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
int ret;
+ /*
+ * If taking the lock fails we have to assume that BL30 is broken. The
+ * best we can do then is to release the resources anyhow.
+ */
ret = meson_sar_adc_lock(indio_dev);
if (ret)
- return ret;
+ dev_err(indio_dev->dev.parent, "Failed to lock ADC (%pE)\n", ERR_PTR(ret));
clk_disable_unprepare(priv->adc_clk);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_ADC_EN, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN);
meson_sar_adc_set_bandgap(indio_dev, false);
- clk_disable_unprepare(priv->core_clk);
-
regulator_disable(priv->vref);
- meson_sar_adc_unlock(indio_dev);
-
- return 0;
+ if (!ret)
+ meson_sar_adc_unlock(indio_dev);
}
static irqreturn_t meson_sar_adc_irq(int irq, void *data)
@@ -1014,7 +1145,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4);
usleep_range(10, 20);
ret = meson_sar_adc_get_sample(indio_dev,
- &indio_dev->channels[7],
+ find_channel_by_num(indio_dev,
+ NUM_MUX_1_VDD_DIV4),
MEAN_AVERAGING, EIGHT_SAMPLES, &value0);
if (ret < 0)
goto out;
@@ -1022,7 +1154,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_MUL3_DIV4);
usleep_range(10, 20);
ret = meson_sar_adc_get_sample(indio_dev,
- &indio_dev->channels[7],
+ find_channel_by_num(indio_dev,
+ NUM_MUX_3_VDD_MUL3_DIV4),
MEAN_AVERAGING, EIGHT_SAMPLES, &value1);
if (ret < 0)
goto out;
@@ -1043,14 +1176,28 @@ out:
return ret;
}
+static int read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ char *label)
+{
+ if (chan->type == IIO_TEMP)
+ return sysfs_emit(label, "temp-sensor\n");
+ if (chan->type == IIO_VOLTAGE && chan->channel >= NUM_MUX_0_VSS)
+ return sysfs_emit(label, "%s\n",
+ chan7_mux_names[chan->channel - NUM_MUX_0_VSS]);
+ if (chan->type == IIO_VOLTAGE)
+ return sysfs_emit(label, "channel-%d\n", chan->channel);
+ return 0;
+}
+
static const struct iio_info meson_sar_adc_iio_info = {
.read_raw = meson_sar_adc_iio_info_read_raw,
+ .read_label = read_label,
};
static const struct meson_sar_adc_param meson_sar_adc_meson8_param = {
.has_bl30_integration = false,
.clock_rate = 1150000,
- .bandgap_reg = MESON_SAR_ADC_DELTA_10,
.regmap_config = &meson_sar_adc_regmap_config_meson8,
.resolution = 10,
.temperature_trimming_bits = 4,
@@ -1061,25 +1208,64 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8_param = {
static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = {
.has_bl30_integration = false,
.clock_rate = 1150000,
- .bandgap_reg = MESON_SAR_ADC_DELTA_10,
.regmap_config = &meson_sar_adc_regmap_config_meson8,
.resolution = 10,
+ .temperature_trimming_bits = 5,
+ .temperature_multiplier = 10,
+ .temperature_divider = 32,
};
static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = {
.has_bl30_integration = true,
.clock_rate = 1200000,
- .bandgap_reg = MESON_SAR_ADC_REG11,
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
.resolution = 10,
+ .vref_voltage = 1,
+ .cmv_select = 1,
};
static const struct meson_sar_adc_param meson_sar_adc_gxl_param = {
.has_bl30_integration = true,
.clock_rate = 1200000,
- .bandgap_reg = MESON_SAR_ADC_REG11,
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
.resolution = 12,
+ .disable_ring_counter = 1,
+ .vref_voltage = 1,
+ .cmv_select = 1,
+};
+
+static const struct meson_sar_adc_param meson_sar_adc_gxlx_param = {
+ .has_bl30_integration = true,
+ .clock_rate = 1200000,
+ .regmap_config = &meson_sar_adc_regmap_config_gxbb,
+ .resolution = 12,
+ .disable_ring_counter = 1,
+ .vref_voltage = 1,
+ .cmv_select = true,
+ .enable_mpll_clock_workaround = true,
+};
+
+static const struct meson_sar_adc_param meson_sar_adc_axg_param = {
+ .has_bl30_integration = true,
+ .clock_rate = 1200000,
+ .regmap_config = &meson_sar_adc_regmap_config_gxbb,
+ .resolution = 12,
+ .disable_ring_counter = 1,
+ .vref_voltage = 1,
+ .has_vref_select = true,
+ .vref_select = VREF_VDDA,
+ .cmv_select = 1,
+};
+
+static const struct meson_sar_adc_param meson_sar_adc_g12a_param = {
+ .has_bl30_integration = false,
+ .clock_rate = 1200000,
+ .regmap_config = &meson_sar_adc_regmap_config_gxbb,
+ .resolution = 12,
+ .disable_ring_counter = 1,
+ .adc_eoc = 1,
+ .has_vref_select = true,
+ .vref_select = VREF_VDDA,
};
static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
@@ -1107,43 +1293,56 @@ static const struct meson_sar_adc_data meson_sar_adc_gxl_data = {
.name = "meson-gxl-saradc",
};
+static const struct meson_sar_adc_data meson_sar_adc_gxlx_data = {
+ .param = &meson_sar_adc_gxlx_param,
+ .name = "meson-gxlx-saradc",
+};
+
static const struct meson_sar_adc_data meson_sar_adc_gxm_data = {
.param = &meson_sar_adc_gxl_param,
.name = "meson-gxm-saradc",
};
static const struct meson_sar_adc_data meson_sar_adc_axg_data = {
- .param = &meson_sar_adc_gxl_param,
+ .param = &meson_sar_adc_axg_param,
.name = "meson-axg-saradc",
};
+static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
+ .param = &meson_sar_adc_g12a_param,
+ .name = "meson-g12a-saradc",
+};
+
static const struct of_device_id meson_sar_adc_of_match[] = {
{
.compatible = "amlogic,meson8-saradc",
.data = &meson_sar_adc_meson8_data,
- },
- {
+ }, {
.compatible = "amlogic,meson8b-saradc",
.data = &meson_sar_adc_meson8b_data,
- },
- {
+ }, {
.compatible = "amlogic,meson8m2-saradc",
.data = &meson_sar_adc_meson8m2_data,
- },
- {
+ }, {
.compatible = "amlogic,meson-gxbb-saradc",
.data = &meson_sar_adc_gxbb_data,
}, {
.compatible = "amlogic,meson-gxl-saradc",
.data = &meson_sar_adc_gxl_data,
}, {
+ .compatible = "amlogic,meson-gxlx-saradc",
+ .data = &meson_sar_adc_gxlx_data,
+ }, {
.compatible = "amlogic,meson-gxm-saradc",
.data = &meson_sar_adc_gxm_data,
}, {
.compatible = "amlogic,meson-axg-saradc",
.data = &meson_sar_adc_axg_data,
+ }, {
+ .compatible = "amlogic,meson-g12a-saradc",
+ .data = &meson_sar_adc_g12a_data,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match);
@@ -1151,97 +1350,70 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
{
const struct meson_sar_adc_data *match_data;
struct meson_sar_adc_priv *priv;
+ struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
- struct resource *res;
void __iomem *base;
int irq, ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
return -ENOMEM;
- }
priv = iio_priv(indio_dev);
init_completion(&priv->done);
- match_data = of_device_get_match_data(&pdev->dev);
- if (!match_data) {
- dev_err(&pdev->dev, "failed to get match data\n");
- return -ENODEV;
- }
+ match_data = of_device_get_match_data(dev);
+ if (!match_data)
+ return dev_err_probe(dev, -ENODEV, "failed to get match data\n");
priv->param = match_data->param;
indio_dev->name = match_data->name;
- indio_dev->dev.parent = &pdev->dev;
- indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &meson_sar_adc_iio_info;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ priv->regmap = devm_regmap_init_mmio(dev, base, priv->param->regmap_config);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap), "failed to init regmap\n");
+
+ irq = irq_of_parse_and_map(dev->of_node, 0);
if (!irq)
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL, "failed to get irq\n");
- ret = devm_request_irq(&pdev->dev, irq, meson_sar_adc_irq, IRQF_SHARED,
- dev_name(&pdev->dev), indio_dev);
+ ret = devm_request_irq(dev, irq, meson_sar_adc_irq, IRQF_SHARED, dev_name(dev), indio_dev);
if (ret)
- return ret;
-
- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- priv->param->regmap_config);
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
+ return dev_err_probe(dev, ret, "failed to request irq\n");
- priv->clkin = devm_clk_get(&pdev->dev, "clkin");
- if (IS_ERR(priv->clkin)) {
- dev_err(&pdev->dev, "failed to get clkin\n");
- return PTR_ERR(priv->clkin);
- }
+ priv->clkin = devm_clk_get(dev, "clkin");
+ if (IS_ERR(priv->clkin))
+ return dev_err_probe(dev, PTR_ERR(priv->clkin), "failed to get clkin\n");
- priv->core_clk = devm_clk_get(&pdev->dev, "core");
- if (IS_ERR(priv->core_clk)) {
- dev_err(&pdev->dev, "failed to get core clk\n");
- return PTR_ERR(priv->core_clk);
- }
+ priv->core_clk = devm_clk_get_enabled(dev, "core");
+ if (IS_ERR(priv->core_clk))
+ return dev_err_probe(dev, PTR_ERR(priv->core_clk), "failed to get core clk\n");
- priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
- if (IS_ERR(priv->adc_clk)) {
- if (PTR_ERR(priv->adc_clk) == -ENOENT) {
- priv->adc_clk = NULL;
- } else {
- dev_err(&pdev->dev, "failed to get adc clk\n");
- return PTR_ERR(priv->adc_clk);
- }
- }
+ priv->adc_clk = devm_clk_get_optional(dev, "adc_clk");
+ if (IS_ERR(priv->adc_clk))
+ return dev_err_probe(dev, PTR_ERR(priv->adc_clk), "failed to get adc clk\n");
- priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
- if (IS_ERR(priv->adc_sel_clk)) {
- if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
- priv->adc_sel_clk = NULL;
- } else {
- dev_err(&pdev->dev, "failed to get adc_sel clk\n");
- return PTR_ERR(priv->adc_sel_clk);
- }
- }
+ priv->adc_sel_clk = devm_clk_get_optional(dev, "adc_sel");
+ if (IS_ERR(priv->adc_sel_clk))
+ return dev_err_probe(dev, PTR_ERR(priv->adc_sel_clk), "failed to get adc_sel clk\n");
/* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
if (!priv->adc_clk) {
ret = meson_sar_adc_clk_init(indio_dev, base);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to init internal clk\n");
}
- priv->vref = devm_regulator_get(&pdev->dev, "vref");
- if (IS_ERR(priv->vref)) {
- dev_err(&pdev->dev, "failed to get vref regulator\n");
- return PTR_ERR(priv->vref);
- }
+ priv->vref = devm_regulator_get(dev, "vref");
+ if (IS_ERR(priv->vref))
+ return dev_err_probe(dev, PTR_ERR(priv->vref), "failed to get vref regulator\n");
priv->calibscale = MILLION;
@@ -1265,19 +1437,23 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
if (ret)
goto err;
+ mutex_init(&priv->lock);
+
ret = meson_sar_adc_hw_enable(indio_dev);
if (ret)
goto err;
ret = meson_sar_adc_calib(indio_dev);
if (ret)
- dev_warn(&pdev->dev, "calibration failed\n");
+ dev_warn(dev, "calibration failed\n");
platform_set_drvdata(pdev, indio_dev);
ret = iio_device_register(indio_dev);
- if (ret)
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register iio device\n");
goto err_hw;
+ }
return 0;
@@ -1287,31 +1463,44 @@ err:
return ret;
}
-static int meson_sar_adc_remove(struct platform_device *pdev)
+static void meson_sar_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
- return meson_sar_adc_hw_disable(indio_dev);
+ meson_sar_adc_hw_disable(indio_dev);
}
-static int __maybe_unused meson_sar_adc_suspend(struct device *dev)
+static int meson_sar_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- return meson_sar_adc_hw_disable(indio_dev);
+ meson_sar_adc_hw_disable(indio_dev);
+
+ clk_disable_unprepare(priv->core_clk);
+
+ return 0;
}
-static int __maybe_unused meson_sar_adc_resume(struct device *dev)
+static int meson_sar_adc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int ret;
+
+ ret = clk_prepare_enable(priv->core_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable core clk\n");
+ return ret;
+ }
return meson_sar_adc_hw_enable(indio_dev);
}
-static SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops,
- meson_sar_adc_suspend, meson_sar_adc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops,
+ meson_sar_adc_suspend, meson_sar_adc_resume);
static struct platform_driver meson_sar_adc_driver = {
.probe = meson_sar_adc_probe,
@@ -1319,7 +1508,7 @@ static struct platform_driver meson_sar_adc_driver = {
.driver = {
.name = "meson-saradc",
.of_match_table = meson_sar_adc_of_match,
- .pm = &meson_sar_adc_pm_ops,
+ .pm = pm_sleep_ptr(&meson_sar_adc_pm_ops),
},
};