Re: [PATCH V2] iio: adc: Add Renesas GyroADC driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



CC linux-renesas-soc

Hi Marek,

On Mon, Jan 9, 2017 at 1:03 AM, Marek Vasut <marek.vasut@xxxxxxxxx> wrote:
> 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 <marek.vasut@xxxxxxxxx>
> Cc: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
> Cc: Simon Horman <horms+renesas@xxxxxxxxxxxx>
> ---
> V2: - Spelling fixes

Thanks for the update!

>     - 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..8

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
> ---
>  .../bindings/iio/adc/renesas,gyroadc.txt           |  52 +++
>  MAINTAINERS                                        |   6 +
>  drivers/iio/adc/Kconfig                            |  10 +
>  drivers/iio/adc/Makefile                           |   1 +
>  drivers/iio/adc/rcar-gyroadc.c                     | 455 +++++++++++++++++++++
>  5 files changed, 524 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
>  create mode 100644 drivers/iio/adc/rcar-gyroadc.c
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt b/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
> new file mode 100644
> index 000000000000..18f5164aefcc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
> @@ -0,0 +1,52 @@
> +* Renesas RCar GyroADC device driver
> +
> +Required properties:
> +- compatible:  Should be "renesas,r8a7791-gyroadc" for regular GyroADC or
> +               "renesas,r8a7792-gyroadc" for a GyroADC without interrupt
> +               block found in R8A7792.

I would have kept "renesas,rcar-gyroadc", too.

Upon closer look, GyroADC in r8a7792 aka R-Car V2H has builtin interrupt
functionality, (SPI IRQ 18), while other variants use the interrupt
functionality of the Speed-pulse I/F (SPI IRQ 236), which is not present
on V2H.

Hence I think we can distinguish between the two variants by looking at
the presence of an "interrupts" property, if we make that mandatory on
V2H. If/when the need arises later, non-V2H variants will need a phandle
to the Speed-pulse I/F to use its interrupt.

Then the driver can just match on "renesas,rcar-gyroadc", instead of any
other single version (all R-Car Gen1, 2, and 3 SoCs) in existence.

> +- reg:         Address and length of the register set for the device
> +- clocks:      References to all the clocks specified in the clock-names
> +               property as specified in
> +               Documentation/devicetree/bindings/clock/clock-bindings.txt.
> +- clock-names: Shall contain "fck" and "if". The "fck" is the GyroADC block
> +               clock, the "if" is the interface clock.
> +- power-domains: Must contain a reference to the PM domain, if available.
> +- renesas,gyroadc-mode:        GyroADC mode of operation, must be either of:
> +                       1 - MB88101A mode, 12bit sampling, 4 channels
> +                       2 - ADCS7476 mode, 15bit sampling, 8 channels
> +                       3 - MAX1162 mode,  16bit sampling, 8 channels

While these mode numbers are documented in the datasheet as such, I'm
wondering whether we should use the actual values to be written to the
MODE_SEL bitfield instead:
  00 = Mode 1
  01 = Mode 2
  10 = Reserved
  11 = Mode 3

That would cater for future versions being extended to 4 modes, renaming
"Mode 3" to "Mode 4" in the process...

Thoughts?

> +Optional properties:
> +- renesas,gyroadc-vref-ch0-supply: Phandle to channel 0 voltage reference regulator.
> +- renesas,gyroadc-vref-ch1-supply: Phandle to channel 1 voltage reference regulator.
> +- renesas,gyroadc-vref-ch2-supply: Phandle to channel 2 voltage reference regulator.
> +- renesas,gyroadc-vref-ch3-supply: Phandle to channel 3 voltage reference regulator.
> +- renesas,gyroadc-vref-ch4-supply: Phandle to channel 4 voltage reference regulator.
> +- renesas,gyroadc-vref-ch5-supply: Phandle to channel 5 voltage reference regulator.
> +- renesas,gyroadc-vref-ch6-supply: Phandle to channel 6 voltage reference regulator.
> +- renesas,gyroadc-vref-ch7-supply: Phandle to channel 7 voltage reference regulator.

Why not an array of phandles? That would simplify parsing.

Also, "vref-supply" seems a fairly standard property name already in wide use.

> +
> +Example:
> +       vref_max1162: regulator-vref-max1162 {
> +               compatible = "regulator-fixed";
> +
> +               regulator-name = "MAX1162 Vref";
> +               regulator-min-microvolt = <4096000>;
> +               regulator-max-microvolt = <4096000>;
> +       };
> +
> +       &adc {
> +               compatible = "renesas,r8a7791-gyroadc";
> +               reg = <0 0xe6e54000 0 64>;
> +               clocks = <&mstp9_clks R8A7791_CLK_GYROADC>, <&clk_65m>;
> +               clock-names = "fck", "if";
> +               power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
> +
> +               pinctrl-0 = <&adc_pins>;
> +               pinctrl-names = "default";
> +
> +               renesas,gyroadc-vref-ch0-supply = <&vref_max1162>;
> +               renesas,gyroadc-vref-ch1-supply = <&vref_max1162>;
> +               renesas,gyroadc-mode = <3>;
> +               status = "okay";
> +       };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 162d904d5cc3..751e760b751b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10271,6 +10271,12 @@ L:     linux-renesas-soc@xxxxxxxxxxxxxxx
>  F:     drivers/net/ethernet/renesas/
>  F:     include/linux/sh_eth.h
>
> +RENESAS RCAR GYROADC DRIVER

R-CAR

> +M:     Marek Vasut <marek.vasut@xxxxxxxxx>
> +L:     linux-iio@xxxxxxxxxxxxxxx
> +S:     Supported
> +F:     drivers/iio/adc/rcar_gyro_adc.c
> +
>  RENESAS USB2 PHY DRIVER
>  M:     Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
>  L:     linux-renesas-soc@xxxxxxxxxxxxxxx
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 99c051490eff..4a4cac7d4e3d 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -408,6 +408,16 @@ 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 RCAR GyroADC driver"

R-Car

> +       depends on ARCH_RCAR_GEN2 || (ARM && COMPILE_TEST)

This may be extended to R-Car Gen2 and Gen3 later.
Note that the former provides ARCH_RCAR_GEN2, but the latter just needs
ARCH_RENESAS

> +       help
> +         Say yes here to build support for the GyroADC found in Renesas
> +         RCar Gen2 SoCs.

R-Car

> +
> +         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 7a40c04c311f..13db7c2bffc8 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -39,6 +39,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_TI_ADC081C) += ti-adc081c.o
> diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
> new file mode 100644
> index 000000000000..a995b81512a7
> --- /dev/null
> +++ b/drivers/iio/adc/rcar-gyroadc.c
> @@ -0,0 +1,455 @@
> +/*
> + * Renesas R-Car GyroADC driver
> + *
> + * Copyright 2016 Marek Vasut <marek.vasut@xxxxxxxxx>
> + *
> + * 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/buffer.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger.h>
> +
> +/* 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 */
> +
> +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;
> +       u32                             buffer[8];
> +};
> +
> +static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv)
> +{
> +       unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000;
> +
> +       /* Stop the GyroADC. */
> +       writel(0, priv->regs + RCAR_GYROADC_START_STOP);
> +
> +       /* Disable IRQ, except on V2H. */
> +       if (priv->model != RCAR_GYROADC_MODEL_R8A7792)

Actually it's r8a7792 (V2H) which has the RCAR_GYROADC_INTENR register,
so the test is reversed.

> +               writel(0, priv->regs + RCAR_GYROADC_INTENR);
> +
> +       /* Set mode and timing. */
> +       writel(priv->mode, priv->regs + RCAR_GYROADC_MODE_SELECT);
> +
> +       if (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A)
> +               writel(clk_mhz * 10, priv->regs + RCAR_GYROADC_CLOCK_LENGTH);
> +       else if (priv->mode == RCAR_GYROADC_MODE_SELECT_2_ADCS7476)
> +               writel(clk_mhz * 5, priv->regs + RCAR_GYROADC_CLOCK_LENGTH);
> +       else if (priv->mode == RCAR_GYROADC_MODE_SELECT_3_MAX1162)
> +               writel(clk_mhz * 5, priv->regs + RCAR_GYROADC_CLOCK_LENGTH);

switch(priv->mode)?

> +       writel(clk_mhz * 1250, priv->regs + RCAR_GYROADC_1_25MS_LENGTH);
> +
> +       /*
> +        * We can possibly turn the sampling on/off on-demand to reduce power
> +        * consumption, but for the sake of quick availability of samples, we
> +        * don't do it now.
> +        */
> +       writel(RCAR_GYROADC_START_STOP_START,
> +              priv->regs + RCAR_GYROADC_START_STOP);
> +
> +       /* Wait for the first conversion to complete. */
> +       udelay(1250);
> +}
> +
> +#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),
> +};
> +
> +/*
> + * NOTE: The data we receive in mode 3 from MAX1162 have MSByte = 0,
> + *       therefore we only use 16bit realbits here instead of 24.
> + */
> +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_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 = priv->vref[chan->channel];
> +       unsigned int datareg = RCAR_GYROADC_REALTIME_DATA(chan->channel);
> +       unsigned int vref;
> +       int ret;
> +
> +       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;
> +
> +               *val = readl(priv->regs + datareg);
> +               *val &= BIT(priv->sample_width) - 1;
> +
> +               iio_device_release_direct_mode(indio_dev);
> +
> +               return IIO_VAL_INT;
> +       case IIO_CHAN_INFO_SCALE:
> +               /* Channel not connected. */
> +               if (!consumer)
> +                       return -EINVAL;
> +
> +               vref = regulator_get_voltage(consumer);
> +               *val = 0;
> +               *val2 = (vref * 1000) / 0x10000;

DIV_ROUND_CLOSEST()?

> +               return IIO_VAL_INT_PLUS_NANO;
> +       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_INTENR;
> +
> +       if (readval == NULL)
> +               return -EINVAL;
> +
> +       if (reg % 4)
> +               return -EINVAL;
> +
> +       /* Handle the V2H case with missing interrupt block. */
> +       if (priv->model == RCAR_GYROADC_MODEL_R8A7792)

Inverted check, r8a7792 has more registers.

> +               maxreg = RCAR_GYROADC_FIFO_STATUS;
> +
> +       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 Gen2 compatible GyroADC */
> +               .compatible     = "renesas,r8a7791-gyroadc",
> +               .data           = (void *)RCAR_GYROADC_MODEL_DEFAULT,
> +       }, {
> +               /* R-Car V2H specialty without interrupt registers. */

with interrupt registers.

> +               .compatible     = "renesas,r8a7792-gyroadc",
> +               .data           = (void *)RCAR_GYROADC_MODEL_R8A7792,
> +       }, {
> +               /* sentinel */
> +       }
> +};
> +
> +MODULE_DEVICE_TABLE(of, rcar_gyroadc_match);
> +
> +static int rcar_gyroadc_init_mode(struct iio_dev *indio_dev)
> +{
> +       struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +       struct device *dev = priv->dev;
> +       int ret, mode;
> +
> +       ret = of_property_read_u32(dev->of_node, "renesas,gyroadc-mode", &mode);
> +       if (ret) {
> +               dev_err(dev, "Failed to get GyroADC mode (ret=%i)\n", ret);
> +               return ret;
> +       } else if (mode == 1) {

switch(mode)

> +               priv->num_channels = 4;
> +               priv->mode = RCAR_GYROADC_MODE_SELECT_1_MB88101A;
> +               priv->sample_width = 12;
> +               indio_dev->channels = rcar_gyroadc_iio_channels_1;
> +               indio_dev->num_channels =
> +                       ARRAY_SIZE(rcar_gyroadc_iio_channels_1);
> +       } else if (mode == 2) {
> +               priv->num_channels = 8;
> +               priv->mode = RCAR_GYROADC_MODE_SELECT_2_ADCS7476;
> +               priv->sample_width = 15;
> +               indio_dev->channels = rcar_gyroadc_iio_channels_2;
> +               indio_dev->num_channels =
> +                       ARRAY_SIZE(rcar_gyroadc_iio_channels_2);
> +       } else if (mode == 3) {
> +               priv->num_channels = 8;
> +               priv->mode = RCAR_GYROADC_MODE_SELECT_3_MAX1162;
> +               priv->sample_width = 16;
> +               indio_dev->channels = rcar_gyroadc_iio_channels_3;
> +               indio_dev->num_channels =
> +                       ARRAY_SIZE(rcar_gyroadc_iio_channels_3);
> +       } else {
> +               dev_err(dev, "Invalid GyroADC mode (mode=%i)\n", mode);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev)
> +{
> +       struct rcar_gyroadc *priv = iio_priv(indio_dev);
> +       int i;

unsigned int

> +
> +       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;
> +       struct regulator *vref;
> +       char name[25];
> +       int i, ret;

unsigned int

> +
> +       for (i = 0; i < priv->num_channels; i++) {
> +               snprintf(name, sizeof(name), "renesas,gyroadc-vref-ch%i", i);
> +
> +               vref = devm_regulator_get_optional(dev, name);
> +               if (IS_ERR(vref)) {
> +                       /*
> +                        * Regulator is not present, which means the channel
> +                        * supply is not connected.
> +                        */
> +                       dev_dbg(dev, "Regulator %s not connected\n", name);
> +                       continue;
> +               }
> +
> +               priv->vref[i] = vref;
> +       }
> +
> +       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_init_mode(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 = dev_name(dev);
> +       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;
> +
> +       pm_runtime_enable(dev);
> +       pm_runtime_get_sync(dev);
> +
> +       ret = clk_prepare_enable(priv->iclk);
> +       if (ret) {
> +               dev_err(dev, "Could not prepare or enable the IF clock.\n");
> +               goto error_clk_if_enable;
> +       }
> +
> +       rcar_gyroadc_hw_init(priv);
> +
> +       ret = iio_device_register(indio_dev);
> +       if (ret) {
> +               dev_err(dev, "Couldn't register IIO device.\n");
> +               goto error_iio_device_register;
> +       }
> +
> +       return 0;
> +
> +error_iio_device_register:
> +       clk_disable_unprepare(priv->iclk);
> +error_clk_if_enable:
> +       pm_runtime_put(dev);
> +       pm_runtime_disable(dev);
> +       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;
> +
> +       /* Stop sampling */
> +       writel(0, priv->regs + RCAR_GYROADC_START_STOP);
> +
> +       iio_device_unregister(indio_dev);
> +       clk_disable_unprepare(priv->iclk);
> +       pm_runtime_put(dev);
> +       pm_runtime_disable(dev);
> +       rcar_gyroadc_deinit_supplies(indio_dev);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver rcar_gyroadc_driver = {
> +       .probe          = rcar_gyroadc_probe,
> +       .remove         = rcar_gyroadc_remove,
> +       .driver         = {
> +               .name           = "rcar-gyroadc",
> +               .of_match_table = rcar_gyroadc_match,
> +       },
> +};
> +
> +module_platform_driver(rcar_gyroadc_driver);
> +
> +MODULE_AUTHOR("Marek Vasut <marek.vasut@xxxxxxxxx>");
> +MODULE_DESCRIPTION("Renesas RCAR GyroADC driver");

R-Car

> +MODULE_LICENSE("GPL");
> --
> 2.11.0

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux