On 27/01/17 23:08, Marek Vasut wrote:
> From: Marek Vasut <[email protected]>
> 
> Add IIO driver for the Renesas RCar GyroADC block. This block is a
> simple 4/8-channel ADC which samples 12/15/24 bits of data every
> cycle from all channels.
> 
> Signed-off-by: Marek Vasut <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Simon Horman <[email protected]>
> Cc: Jonathan Cameron <[email protected]>
> Cc: [email protected]
> Cc: Wolfram Sang <[email protected]>
Applied to the togreg branch of iio.git and pushed out as testing for the
autobuilders to play with it.

Thanks,

Jonathan
> ---
> V2: - Spelling fixes
>     - Rename the driver source file to rcar-gyroadc
>     - Rework the channel sample width handling
>     - Use iio_device_claim_mode_direct()
>     - Rename "renesas,rcar-gyroadc" to "renesas,r8a7791-gyroadc" and
>       rename "renesas,rcar-gyroadc-r8a7792" to "renesas,r8a7792-gyroadc"
>       to match the new naming scheme (WARNING: scif uses the old one!)
>     - Switch to using regulators for channel voltage reference, add new
>       properties renesas,gyroadc-vref-chN-supply for N in 0..7
>     - Handle vref regulators as optional to, make channels without
>       vref regulator return EINVAL on read.
>     - Fix module license to GPL
>     - Drop interrupt.h include
>     - Rename clk to iclk
>     - Rename RCar to R-Car
>     - Rework the invalid mode handling
>     - Don't print error message on EPROBE_DEFER
>     - Drop fclk handling, use runtime PM for that instead
> V3: - More R-Car spelling fixes
>     - Flip checks for V2H, since that's the only one that has
>       interrupt registers
>     - Replace if-else statement with switch statement in init_mode
>     - Use unsigned types where applicable
>     - Rework timing calculation slightly to drop if-else block
>     - Use DIV_ROUND_CLOSEST
> V4: - Add renesas,rcar-gyroadc fallback compatible string into the bindings
>     - Rework the ADC bindings to use per-channel subdevs
>     - Support more compatible ADC chips
> V5: - Reword the DT bindings, improve the description of the modes
>     - Improve the description in Kconfig
>     - Implement special DT bindings for the MB88101A 4-channel ADC and
>       add special handling for this chip into the driver.
>     - Add missing ADC stop on failure, wrap it into a function
>     - Fail hard in case the DT properties are incorrect or missing
>     - Fix reporting of scale, so that channel * scale value is in mV
>     - Use fractional scale instead of int plus nano
>     - Use pm_runtime to disable the sampling 2 seconds after last used
> V6: - Replace the indio_dev->name with "rcar-gyroadc" instead of OF node name
> V7: - Split the DT bindings out of this patch
> V8: - No change
> V9: - No change
> ---
>  MAINTAINERS                    |   6 +
>  drivers/iio/adc/Kconfig        |  13 +
>  drivers/iio/adc/Makefile       |   1 +
>  drivers/iio/adc/rcar-gyroadc.c | 631 
> +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 651 insertions(+)
>  create mode 100644 drivers/iio/adc/rcar-gyroadc.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0a2e5fe55249..7475db480519 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10445,6 +10445,12 @@ L:   [email protected]
>  F:   drivers/net/ethernet/renesas/
>  F:   include/linux/sh_eth.h
>  
> +RENESAS R-CAR GYROADC DRIVER
> +M:   Marek Vasut <[email protected]>
> +L:   [email protected]
> +S:   Supported
> +F:   drivers/iio/adc/rcar_gyro_adc.c
> +
>  RENESAS USB2 PHY DRIVER
>  M:   Yoshihiro Shimoda <[email protected]>
>  L:   [email protected]
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 9c8b558ba19e..2f7a8f3dbaf9 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -430,6 +430,19 @@ config QCOM_SPMI_VADC
>         To compile this driver as a module, choose M here: the module will
>         be called qcom-spmi-vadc.
>  
> +config RCAR_GYRO_ADC
> +     tristate "Renesas R-Car GyroADC driver"
> +     depends on ARCH_RCAR_GEN2 || (ARM && COMPILE_TEST)
> +     help
> +       Say yes here to build support for the GyroADC found in Renesas
> +       R-Car Gen2 SoCs. This block is a simple SPI offload engine for
> +       reading data out of attached compatible ADCs in a round-robin
> +       fashion. Up to 4 or 8 ADC channels are supported by this block,
> +       depending on which ADCs are attached.
> +
> +       To compile this driver as a module, choose M here: the
> +       module will be called rcar-gyroadc.
> +
>  config ROCKCHIP_SARADC
>       tristate "Rockchip SARADC driver"
>       depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index d36c4be8d1fc..4bcd0edca4eb 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -41,6 +41,7 @@ obj-$(CONFIG_NAU7802) += nau7802.o
>  obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
>  obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
>  obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
> +obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
>  obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
>  obj-$(CONFIG_STX104) += stx104.o
>  obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
> diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
> new file mode 100644
> index 000000000000..0c44f72c32a8
> --- /dev/null
> +++ b/drivers/iio/adc/rcar-gyroadc.c
> @@ -0,0 +1,631 @@
> +/*
> + * Renesas R-Car GyroADC driver
> + *
> + * Copyright 2016 Marek Vasut <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/of_platform.h>
> +#include <linux/err.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger.h>
> +
> +#define DRIVER_NAME                          "rcar-gyroadc"
> +
> +/* GyroADC registers. */
> +#define RCAR_GYROADC_MODE_SELECT             0x00
> +#define RCAR_GYROADC_MODE_SELECT_1_MB88101A  0x0
> +#define RCAR_GYROADC_MODE_SELECT_2_ADCS7476  0x1
> +#define RCAR_GYROADC_MODE_SELECT_3_MAX1162   0x3
> +
> +#define RCAR_GYROADC_START_STOP                      0x04
> +#define RCAR_GYROADC_START_STOP_START                BIT(0)
> +
> +#define RCAR_GYROADC_CLOCK_LENGTH            0x08
> +#define RCAR_GYROADC_1_25MS_LENGTH           0x0c
> +
> +#define RCAR_GYROADC_REALTIME_DATA(ch)               (0x10 + ((ch) * 4))
> +#define RCAR_GYROADC_100MS_ADDED_DATA(ch)    (0x30 + ((ch) * 4))
> +#define RCAR_GYROADC_10MS_AVG_DATA(ch)               (0x50 + ((ch) * 4))
> +
> +#define RCAR_GYROADC_FIFO_STATUS             0x70
> +#define RCAR_GYROADC_FIFO_STATUS_EMPTY(ch)   BIT(0 + (4 * (ch)))
> +#define RCAR_GYROADC_FIFO_STATUS_FULL(ch)    BIT(1 + (4 * (ch)))
> +#define RCAR_GYROADC_FIFO_STATUS_ERROR(ch)   BIT(2 + (4 * (ch)))
> +
> +#define RCAR_GYROADC_INTR                    0x74
> +#define RCAR_GYROADC_INTR_INT                        BIT(0)
> +
> +#define RCAR_GYROADC_INTENR                  0x78
> +#define RCAR_GYROADC_INTENR_INTEN            BIT(0)
> +
> +#define RCAR_GYROADC_SAMPLE_RATE             800     /* Hz */
> +
> +#define RCAR_GYROADC_RUNTIME_PM_DELAY_MS     2000
> +
> +enum rcar_gyroadc_model {
> +     RCAR_GYROADC_MODEL_DEFAULT,
> +     RCAR_GYROADC_MODEL_R8A7792,
> +};
> +
> +struct rcar_gyroadc {
> +     struct device                   *dev;
> +     void __iomem                    *regs;
> +     struct clk                      *iclk;
> +     struct regulator                *vref[8];
> +     unsigned int                    num_channels;
> +     enum rcar_gyroadc_model         model;
> +     unsigned int                    mode;
> +     unsigned int                    sample_width;
> +};
> +
> +static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv)
> +{
> +     const unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000;
> +     const unsigned long clk_mul =
> +             (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5;
> +     unsigned long clk_len = clk_mhz * clk_mul;
> +
> +     /*
> +      * According to the R-Car Gen2 datasheet Rev. 1.01, Sept 08 2014,
> +      * page 77-7, clock length must be even number. If it's odd number,
> +      * add one.
> +      */
> +     if (clk_len & 1)
> +             clk_len++;
> +
> +     /* Stop the GyroADC. */
> +     writel(0, priv->regs + RCAR_GYROADC_START_STOP);
> +
> +     /* Disable IRQ on V2H. */
> +     if (priv->model == RCAR_GYROADC_MODEL_R8A7792)
> +             writel(0, priv->regs + RCAR_GYROADC_INTENR);
> +
> +     /* Set mode and timing. */
> +     writel(priv->mode, priv->regs + RCAR_GYROADC_MODE_SELECT);
> +     writel(clk_len, priv->regs + RCAR_GYROADC_CLOCK_LENGTH);
> +     writel(clk_mhz * 1250, priv->regs + RCAR_GYROADC_1_25MS_LENGTH);
> +}
> +
> +static void rcar_gyroadc_hw_start(struct rcar_gyroadc *priv)
> +{
> +     /* Start sampling. */
> +     writel(RCAR_GYROADC_START_STOP_START,
> +            priv->regs + RCAR_GYROADC_START_STOP);
> +
> +     /*
> +      * Wait for the first conversion to complete. This is longer than
> +      * the 1.25 mS in the datasheet because 1.25 mS is not enough for
> +      * the hardware to deliver the first sample and the hardware does
> +      * then return zeroes instead of valid data.
> +      */
> +     mdelay(3);
> +}
> +
> +static void rcar_gyroadc_hw_stop(struct rcar_gyroadc *priv)
> +{
> +     /* Stop the GyroADC. */
> +     writel(0, priv->regs + RCAR_GYROADC_START_STOP);
> +}
> +
> +#define RCAR_GYROADC_CHAN(_idx) {                            \
> +     .type                   = IIO_VOLTAGE,                  \
> +     .indexed                = 1,                            \
> +     .channel                = (_idx),                       \
> +     .info_mask_separate     = BIT(IIO_CHAN_INFO_RAW) |      \
> +                               BIT(IIO_CHAN_INFO_SCALE),     \
> +     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> +}
> +
> +static const struct iio_chan_spec rcar_gyroadc_iio_channels_1[] = {
> +     RCAR_GYROADC_CHAN(0),
> +     RCAR_GYROADC_CHAN(1),
> +     RCAR_GYROADC_CHAN(2),
> +     RCAR_GYROADC_CHAN(3),
> +};
> +
> +static const struct iio_chan_spec rcar_gyroadc_iio_channels_2[] = {
> +     RCAR_GYROADC_CHAN(0),
> +     RCAR_GYROADC_CHAN(1),
> +     RCAR_GYROADC_CHAN(2),
> +     RCAR_GYROADC_CHAN(3),
> +     RCAR_GYROADC_CHAN(4),
> +     RCAR_GYROADC_CHAN(5),
> +     RCAR_GYROADC_CHAN(6),
> +     RCAR_GYROADC_CHAN(7),
> +};
> +
> +static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = {
> +     RCAR_GYROADC_CHAN(0),
> +     RCAR_GYROADC_CHAN(1),
> +     RCAR_GYROADC_CHAN(2),
> +     RCAR_GYROADC_CHAN(3),
> +     RCAR_GYROADC_CHAN(4),
> +     RCAR_GYROADC_CHAN(5),
> +     RCAR_GYROADC_CHAN(6),
> +     RCAR_GYROADC_CHAN(7),
> +};
> +
> +static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on)
> +{
> +     struct device *dev = priv->dev;
> +     int ret;
> +
> +     if (on) {
> +             ret = pm_runtime_get_sync(dev);
> +             if (ret < 0)
> +                     pm_runtime_put_noidle(dev);
> +     } else {
> +             pm_runtime_mark_last_busy(dev);
> +             ret = pm_runtime_put_autosuspend(dev);
> +     }
> +
> +     return ret;
> +}
> +
> +static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
> +                              struct iio_chan_spec const *chan,
> +                              int *val, int *val2, long mask)
> +{
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +     struct regulator *consumer;
> +     unsigned int datareg = RCAR_GYROADC_REALTIME_DATA(chan->channel);
> +     unsigned int vref;
> +     int ret;
> +
> +     /*
> +      * MB88101 is special in that it has only single regulator for
> +      * all four channels.
> +      */
> +     if (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A)
> +             consumer = priv->vref[0];
> +     else
> +             consumer = priv->vref[chan->channel];
> +
> +     switch (mask) {
> +     case IIO_CHAN_INFO_RAW:
> +             if (chan->type != IIO_VOLTAGE)
> +                     return -EINVAL;
> +
> +             /* Channel not connected. */
> +             if (!consumer)
> +                     return -EINVAL;
> +
> +             ret = iio_device_claim_direct_mode(indio_dev);
> +             if (ret)
> +                     return ret;
> +
> +             ret = rcar_gyroadc_set_power(priv, true);
> +             if (ret < 0) {
> +                     iio_device_release_direct_mode(indio_dev);
> +                     return ret;
> +             }
> +
> +             *val = readl(priv->regs + datareg);
> +             *val &= BIT(priv->sample_width) - 1;
> +
> +             ret = rcar_gyroadc_set_power(priv, false);
> +             iio_device_release_direct_mode(indio_dev);
> +             if (ret < 0)
> +                     return ret;
> +
> +             return IIO_VAL_INT;
> +     case IIO_CHAN_INFO_SCALE:
> +             /* Channel not connected. */
> +             if (!consumer)
> +                     return -EINVAL;
> +
> +             vref = regulator_get_voltage(consumer);
> +             *val = vref / 1000;
> +             *val2 = 1 << priv->sample_width;
> +
> +             return IIO_VAL_FRACTIONAL;
> +     case IIO_CHAN_INFO_SAMP_FREQ:
> +             *val = RCAR_GYROADC_SAMPLE_RATE;
> +
> +             return IIO_VAL_INT;
> +     default:
> +             return -EINVAL;
> +     }
> +}
> +
> +static int rcar_gyroadc_reg_access(struct iio_dev *indio_dev,
> +                                unsigned int reg, unsigned int writeval,
> +                                unsigned int *readval)
> +{
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +     unsigned int maxreg = RCAR_GYROADC_FIFO_STATUS;
> +
> +     if (readval == NULL)
> +             return -EINVAL;
> +
> +     if (reg % 4)
> +             return -EINVAL;
> +
> +     /* Handle the V2H case with extra interrupt block. */
> +     if (priv->model == RCAR_GYROADC_MODEL_R8A7792)
> +             maxreg = RCAR_GYROADC_INTENR;
> +
> +     if (reg > maxreg)
> +             return -EINVAL;
> +
> +     *readval = readl(priv->regs + reg);
> +
> +     return 0;
> +}
> +
> +static const struct iio_info rcar_gyroadc_iio_info = {
> +     .driver_module          = THIS_MODULE,
> +     .read_raw               = rcar_gyroadc_read_raw,
> +     .debugfs_reg_access     = rcar_gyroadc_reg_access,
> +};
> +
> +static const struct of_device_id rcar_gyroadc_match[] = {
> +     {
> +             /* R-Car compatible GyroADC */
> +             .compatible     = "renesas,rcar-gyroadc",
> +             .data           = (void *)RCAR_GYROADC_MODEL_DEFAULT,
> +     }, {
> +             /* R-Car V2H specialty with interrupt registers. */
> +             .compatible     = "renesas,r8a7792-gyroadc",
> +             .data           = (void *)RCAR_GYROADC_MODEL_R8A7792,
> +     }, {
> +             /* sentinel */
> +     }
> +};
> +
> +MODULE_DEVICE_TABLE(of, rcar_gyroadc_match);
> +
> +static const struct of_device_id rcar_gyroadc_child_match[] = {
> +     /* Mode 1 ADCs */
> +     {
> +             .compatible     = "fujitsu,mb88101a",
> +             .data           = (void *)RCAR_GYROADC_MODE_SELECT_1_MB88101A,
> +     },
> +     /* Mode 2 ADCs */
> +     {
> +             .compatible     = "ti,adcs7476",
> +             .data           = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476,
> +     }, {
> +             .compatible     = "ti,adc121",
> +             .data           = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476,
> +     }, {
> +             .compatible     = "adi,ad7476",
> +             .data           = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476,
> +     },
> +     /* Mode 3 ADCs */
> +     {
> +             .compatible     = "maxim,max1162",
> +             .data           = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162,
> +     }, {
> +             .compatible     = "maxim,max11100",
> +             .data           = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162,
> +     },
> +     { /* sentinel */ }
> +};
> +
> +static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
> +{
> +     const struct of_device_id *of_id;
> +     const struct iio_chan_spec *channels;
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +     struct device *dev = priv->dev;
> +     struct device_node *np = dev->of_node;
> +     struct device_node *child;
> +     struct regulator *vref;
> +     unsigned int reg;
> +     unsigned int adcmode, childmode;
> +     unsigned int sample_width;
> +     unsigned int num_channels;
> +     int ret, first = 1;
> +
> +     for_each_child_of_node(np, child) {
> +             of_id = of_match_node(rcar_gyroadc_child_match, child);
> +             if (!of_id) {
> +                     dev_err(dev, "Ignoring unsupported ADC \"%s\".",
> +                             child->name);
> +                     continue;
> +             }
> +
> +             childmode = (unsigned int)of_id->data;
> +             switch (childmode) {
> +             case RCAR_GYROADC_MODE_SELECT_1_MB88101A:
> +                     sample_width = 12;
> +                     channels = rcar_gyroadc_iio_channels_1;
> +                     num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_1);
> +                     break;
> +             case RCAR_GYROADC_MODE_SELECT_2_ADCS7476:
> +                     sample_width = 15;
> +                     channels = rcar_gyroadc_iio_channels_2;
> +                     num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_2);
> +                     break;
> +             case RCAR_GYROADC_MODE_SELECT_3_MAX1162:
> +                     sample_width = 16;
> +                     channels = rcar_gyroadc_iio_channels_3;
> +                     num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3);
> +                     break;
> +             }
> +
> +             /*
> +              * MB88101 is special in that it's only a single chip taking
> +              * up all the CHS lines. Thus, the DT binding is also special
> +              * and has no reg property. If we run into such ADC, handle
> +              * it here.
> +              */
> +             if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) {
> +                     reg = 0;
> +             } else {
> +                     ret = of_property_read_u32(child, "reg", &reg);
> +                     if (ret) {
> +                             dev_err(dev,
> +                                     "Failed to get child reg property of 
> ADC \"%s\".\n",
> +                                     child->name);
> +                             return ret;
> +                     }
> +
> +                     /* Channel number is too high. */
> +                     if (reg >= num_channels) {
> +                             dev_err(dev,
> +                                     "Only %i channels supported with %s, 
> but reg = <%i>.\n",
> +                                     num_channels, child->name, reg);
> +                             return ret;
> +                     }
> +             }
> +
> +             /* Child node selected different mode than the rest. */
> +             if (!first && (adcmode != childmode)) {
> +                     dev_err(dev,
> +                             "Channel %i uses different ADC mode than the 
> rest.\n",
> +                             reg);
> +                     return ret;
> +             }
> +
> +             /* Channel is valid, grab the regulator. */
> +             dev->of_node = child;
> +             vref = devm_regulator_get(dev, "vref");
> +             dev->of_node = np;
> +             if (IS_ERR(vref)) {
> +                     dev_dbg(dev, "Channel %i 'vref' supply not 
> connected.\n",
> +                             reg);
> +                     return PTR_ERR(vref);
> +             }
> +
> +             priv->vref[reg] = vref;
> +
> +             if (!first)
> +                     continue;
> +
> +             /* First child node which passed sanity tests. */
> +             adcmode = childmode;
> +             first = 0;
> +
> +             priv->num_channels = num_channels;
> +             priv->mode = childmode;
> +             priv->sample_width = sample_width;
> +
> +             indio_dev->channels = channels;
> +             indio_dev->num_channels = num_channels;
> +
> +             /*
> +              * MB88101 is special and we only have one such device
> +              * attached to the GyroADC at a time, so if we found it,
> +              * we can stop parsing here.
> +              */
> +             if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A)
> +                     break;
> +     }
> +
> +     if (first) {
> +             dev_err(dev, "No valid ADC channels found, aborting.\n");
> +             return -EINVAL;
> +     }
> +
> +     return 0;
> +}
> +
> +static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev)
> +{
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +     unsigned int i;
> +
> +     for (i = 0; i < priv->num_channels; i++) {
> +             if (!priv->vref[i])
> +                     continue;
> +
> +             regulator_disable(priv->vref[i]);
> +     }
> +}
> +
> +static int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev)
> +{
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +     struct device *dev = priv->dev;
> +     unsigned int i;
> +     int ret;
> +
> +     for (i = 0; i < priv->num_channels; i++) {
> +             if (!priv->vref[i])
> +                     continue;
> +
> +             ret = regulator_enable(priv->vref[i]);
> +             if (ret) {
> +                     dev_err(dev, "Failed to enable regulator %i (ret=%i)\n",
> +                             i, ret);
> +                     goto err;
> +             }
> +     }
> +
> +     return 0;
> +
> +err:
> +     rcar_gyroadc_deinit_supplies(indio_dev);
> +     return ret;
> +}
> +
> +static int rcar_gyroadc_probe(struct platform_device *pdev)
> +{
> +     const struct of_device_id *of_id =
> +             of_match_device(rcar_gyroadc_match, &pdev->dev);
> +     struct device *dev = &pdev->dev;
> +     struct rcar_gyroadc *priv;
> +     struct iio_dev *indio_dev;
> +     struct resource *mem;
> +     int ret;
> +
> +     indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
> +     if (!indio_dev) {
> +             dev_err(dev, "Failed to allocate IIO device.\n");
> +             return -ENOMEM;
> +     }
> +
> +     priv = iio_priv(indio_dev);
> +     priv->dev = dev;
> +
> +     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     priv->regs = devm_ioremap_resource(dev, mem);
> +     if (IS_ERR(priv->regs))
> +             return PTR_ERR(priv->regs);
> +
> +     priv->iclk = devm_clk_get(dev, "if");
> +     if (IS_ERR(priv->iclk)) {
> +             ret = PTR_ERR(priv->iclk);
> +             if (ret != -EPROBE_DEFER)
> +                     dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret);
> +             return ret;
> +     }
> +
> +     ret = rcar_gyroadc_parse_subdevs(indio_dev);
> +     if (ret)
> +             return ret;
> +
> +     ret = rcar_gyroadc_init_supplies(indio_dev);
> +     if (ret)
> +             return ret;
> +
> +     priv->model = (enum rcar_gyroadc_model)of_id->data;
> +
> +     platform_set_drvdata(pdev, indio_dev);
> +
> +     indio_dev->name = DRIVER_NAME;
> +     indio_dev->dev.parent = dev;
> +     indio_dev->dev.of_node = pdev->dev.of_node;
> +     indio_dev->info = &rcar_gyroadc_iio_info;
> +     indio_dev->modes = INDIO_DIRECT_MODE;
> +
> +     ret = clk_prepare_enable(priv->iclk);
> +     if (ret) {
> +             dev_err(dev, "Could not prepare or enable the IF clock.\n");
> +             goto err_clk_if_enable;
> +     }
> +
> +     pm_runtime_set_autosuspend_delay(dev, RCAR_GYROADC_RUNTIME_PM_DELAY_MS);
> +     pm_runtime_use_autosuspend(dev);
> +     pm_runtime_enable(dev);
> +
> +     pm_runtime_get_sync(dev);
> +     rcar_gyroadc_hw_init(priv);
> +     rcar_gyroadc_hw_start(priv);
> +
> +     ret = iio_device_register(indio_dev);
> +     if (ret) {
> +             dev_err(dev, "Couldn't register IIO device.\n");
> +             goto err_iio_device_register;
> +     }
> +
> +     pm_runtime_put_sync(dev);
> +
> +     return 0;
> +
> +err_iio_device_register:
> +     rcar_gyroadc_hw_stop(priv);
> +     pm_runtime_put_sync(dev);
> +     pm_runtime_disable(dev);
> +     pm_runtime_set_suspended(dev);
> +     clk_disable_unprepare(priv->iclk);
> +err_clk_if_enable:
> +     rcar_gyroadc_deinit_supplies(indio_dev);
> +
> +     return ret;
> +}
> +
> +static int rcar_gyroadc_remove(struct platform_device *pdev)
> +{
> +     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +     struct device *dev = priv->dev;
> +
> +     iio_device_unregister(indio_dev);
> +     pm_runtime_get_sync(dev);
> +     rcar_gyroadc_hw_stop(priv);
> +     pm_runtime_put_sync(dev);
> +     pm_runtime_disable(dev);
> +     pm_runtime_set_suspended(dev);
> +     clk_disable_unprepare(priv->iclk);
> +     rcar_gyroadc_deinit_supplies(indio_dev);
> +
> +     return 0;
> +}
> +
> +#if defined(CONFIG_PM)
> +static int rcar_gyroadc_suspend(struct device *dev)
> +{
> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +
> +     rcar_gyroadc_hw_stop(priv);
> +
> +     return 0;
> +}
> +
> +static int rcar_gyroadc_resume(struct device *dev)
> +{
> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +     struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +
> +     rcar_gyroadc_hw_start(priv);
> +
> +     return 0;
> +}
> +#endif
> +
> +static const struct dev_pm_ops rcar_gyroadc_pm_ops = {
> +     SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL)
> +};
> +
> +static struct platform_driver rcar_gyroadc_driver = {
> +     .probe          = rcar_gyroadc_probe,
> +     .remove         = rcar_gyroadc_remove,
> +     .driver         = {
> +             .name           = DRIVER_NAME,
> +             .of_match_table = rcar_gyroadc_match,
> +             .pm             = &rcar_gyroadc_pm_ops,
> +     },
> +};
> +
> +module_platform_driver(rcar_gyroadc_driver);
> +
> +MODULE_AUTHOR("Marek Vasut <[email protected]>");
> +MODULE_DESCRIPTION("Renesas R-Car GyroADC driver");
> +MODULE_LICENSE("GPL");
> 

Reply via email to