]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge tag 'iio-for-3.19a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Nov 2014 19:42:48 +0000 (11:42 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Nov 2014 19:42:48 +0000 (11:42 -0800)
Jonathan writes:

First round of new drivers, features and cleanups for IIO in the 3.19 cycle.

New drivers / supported parts
* rockchip - rk3066-tsadc variant
* si7020 humidity and temperature sensor
* mcp320x - add mcp3001, mcp3002, mcp3004, mcp3008, mcp3201, mcp3202
* bmp280 pressure and temperature sensor
* Qualcomm SPMI PMIC current ADC driver
* Exynos_adc - support exynos7

New features
* vf610-adc - add temperature sensor support
* Documentation of current attributes, scaled pressure, offset and
  scaled humidity, RGBC intensity gain factor and scale applied to
  differential voltage channels.
* Bring iio_event_monitor up to date with newer modifiers.
* Add of_xlate function to allow for complex channel mappings from the
  device tree.
* Add -g parameter to generic_buffer example to allow for devices with
  directly fed (no trigger) buffers.
* Move exynos driver over to syscon for PMU register access.

Cleanups, fixes for new drivers
* lis3l02dq drop an unneeded else.
* st sensors - renam st_sensors to st_sensor_settings (for clarity)
* st sensors - drop an unused parameter from all the probe utility
  functions.
* vf610 better error handling and tidy up.
* si7020 - cleanups following merge
* as3935 - drop some unnecessary semicolons.
* bmp280 - fix the pressure calculation.

47 files changed:
Documentation/ABI/testing/sysfs-bus-iio
Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4x12.dtsi
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5420.dtsi
drivers/iio/accel/st_accel.h
drivers/iio/accel/st_accel_core.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/st_accel_spi.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/exynos_adc.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/qcom-spmi-iadc.c [new file with mode: 0644]
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/common/st_sensors/st_sensors_i2c.c
drivers/iio/common/st_sensors/st_sensors_spi.c
drivers/iio/gyro/st_gyro.h
drivers/iio/gyro/st_gyro_core.c
drivers/iio/gyro/st_gyro_i2c.c
drivers/iio/gyro/st_gyro_spi.c
drivers/iio/humidity/Kconfig
drivers/iio/humidity/Makefile
drivers/iio/humidity/si7020.c [new file with mode: 0644]
drivers/iio/inkern.c
drivers/iio/magnetometer/st_magn.h
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/magnetometer/st_magn_i2c.c
drivers/iio/magnetometer/st_magn_spi.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/Makefile
drivers/iio/pressure/bmp280.c [new file with mode: 0644]
drivers/iio/pressure/st_pressure.h
drivers/iio/pressure/st_pressure_buffer.c
drivers/iio/pressure/st_pressure_core.c
drivers/iio/pressure/st_pressure_i2c.c
drivers/iio/pressure/st_pressure_spi.c
drivers/iio/proximity/as3935.c
drivers/staging/iio/Documentation/generic_buffer.c
drivers/staging/iio/accel/lis3l02dq_ring.c
include/linux/iio/common/st_sensors.h
include/linux/iio/iio.h

index d760b0224ef7b99f30632f07bf7a0986c6ce92e5..117521dbf2b3eb074463380c70ffb790ab235dee 100644 (file)
@@ -200,6 +200,13 @@ Description:
                Raw pressure measurement from channel Y. Units after
                application of scale and offset are kilopascal.
 
+What:          /sys/bus/iio/devices/iio:deviceX/in_pressureY_input
+What:          /sys/bus/iio/devices/iio:deviceX/in_pressure_input
+KernelVersion: 3.8
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Scaled pressure measurement from channel Y, in kilopascal.
+
 What:          /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_raw
 KernelVersion: 3.14
 Contact:       linux-iio@vger.kernel.org
@@ -231,6 +238,7 @@ What:               /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
 What:          /sys/bus/iio/devices/iio:deviceX/in_temp_offset
 What:          /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
 What:          /sys/bus/iio/devices/iio:deviceX/in_pressure_offset
+What:          /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset
 KernelVersion: 2.6.35
 Contact:       linux-iio@vger.kernel.org
 Description:
@@ -251,6 +259,7 @@ Description:
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
 What:          /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
 What:          /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
 What:          /sys/bus/iio/devices/iio:deviceX/in_accel_scale
@@ -266,6 +275,7 @@ What:               /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_sca
 What:          /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
 What:          /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
 What:          /sys/bus/iio/devices/iio:deviceX/in_pressure_scale
+What:          /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
 KernelVersion: 2.6.35
 Contact:       linux-iio@vger.kernel.org
 Description:
@@ -328,6 +338,10 @@ Description:
                are listed in this attribute.
 
 What           /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
+What:          /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain
+What:          /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain
+What:          /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain
+What:          /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_hardwaregain
 KernelVersion: 2.6.35
 Contact:       linux-iio@vger.kernel.org
 Description:
@@ -1028,3 +1042,12 @@ Contact: linux-iio@vger.kernel.org
 Description:
                Raw value of rotation from true/magnetic north measured with
                or without compensation from tilt sensors.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_currentX_raw
+KernelVersion: 3.18
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Raw current measurement from channel X. Units are in milliamps
+               after application of scale and offset. If no offset or scale is
+               present, output should be considered as processed with the
+               unit in milliamps.
index 709efaa30841d8e92b232ebb0ed61b4eccccff88..f46ca9a316a2f4471befb32d517508939f661ab2 100644 (file)
@@ -16,6 +16,8 @@ Required properties:
                                future controllers.
                        Must be "samsung,exynos3250-adc" for
                                controllers compatible with ADC of Exynos3250.
+                       Must be "samsung,exynos7-adc" for
+                               the ADC in Exynos7 and compatibles
                        Must be "samsung,s3c2410-adc" for
                                the ADC in s3c2410 and compatibles
                        Must be "samsung,s3c2416-adc" for
@@ -43,13 +45,16 @@ Required properties:
                                   compatible ADC block)
 - vdd-supply           VDD input supply.
 
+- samsung,syscon-phandle Contains the PMU system controller node
+                       (To access the ADC_PHY register on Exynos5250/5420/5800/3250)
+
 Note: child nodes can be added for auto probing from device tree.
 
 Example: adding device info in dtsi file
 
 adc: adc@12D10000 {
        compatible = "samsung,exynos-adc-v1";
-       reg = <0x12D10000 0x100>, <0x10040718 0x4>;
+       reg = <0x12D10000 0x100>;
        interrupts = <0 106 0>;
        #io-channel-cells = <1>;
        io-channel-ranges;
@@ -58,13 +63,14 @@ adc: adc@12D10000 {
        clock-names = "adc";
 
        vdd-supply = <&buck5_reg>;
+       samsung,syscon-phandle = <&pmu_system_controller>;
 };
 
 Example: adding device info in dtsi file for Exynos3250 with additional sclk
 
 adc: adc@126C0000 {
        compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
-       reg = <0x126C0000 0x100>, <0x10020718 0x4>;
+       reg = <0x126C0000 0x100>;
        interrupts = <0 137 0>;
        #io-channel-cells = <1>;
        io-channel-ranges;
@@ -73,6 +79,7 @@ adc: adc@126C0000 {
        clock-names = "adc", "sclk";
 
        vdd-supply = <&buck5_reg>;
+       samsung,syscon-phandle = <&pmu_system_controller>;
 };
 
 Example: Adding child nodes in dts file
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.txt
new file mode 100644 (file)
index 0000000..4e36d6e
--- /dev/null
@@ -0,0 +1,46 @@
+Qualcomm's SPMI PMIC current ADC
+
+QPNP PMIC current ADC (IADC) provides interface to clients to read current.
+A 16 bit ADC is used for current measurements. IADC can measure the current
+through an external resistor (channel 1) or internal (built-in) resistor
+(channel 0). When using an external resistor it is to be described by
+qcom,external-resistor-micro-ohms property.
+
+IADC node:
+
+- compatible:
+    Usage: required
+    Value type: <string>
+    Definition: Should contain "qcom,spmi-iadc".
+
+- reg:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: IADC base address and length in the SPMI PMIC register map
+
+- interrupts:
+    Usage: optional
+    Value type: <prop-encoded-array>
+    Definition: End of ADC conversion.
+
+- qcom,external-resistor-micro-ohms:
+    Usage: optional
+    Value type: <u32>
+    Definition: Sense resister value in micro Ohm.
+                If not defined value of 10000 micro Ohms will be used.
+
+Example:
+       /* IADC node */
+       pmic_iadc: iadc@3600 {
+               compatible = "qcom,spmi-iadc";
+               reg = <0x3600 0x100>;
+               interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
+               qcom,external-resistor-micro-ohms = <10000>;
+               #io-channel-cells  = <1>;
+       };
+
+       /* IIO client node */
+       bat {
+               io-channels = <&pmic_iadc  0>;
+               io-channel-names = "iadc";
+       };
index 5d3ec1df226d4c5c2db4611b604a67bd7538c8aa..a9a5fe19ff2a037db14de181280196cce7745d3d 100644 (file)
@@ -1,7 +1,7 @@
 Rockchip Successive Approximation Register (SAR) A/D Converter bindings
 
 Required properties:
-- compatible: Should be "rockchip,saradc"
+- compatible: Should be "rockchip,saradc" or "rockchip,rk3066-tsadc"
 - reg: physical base address of the controller and length of memory mapped
        region.
 - interrupts: The interrupt number to the cpu. The interrupt specifier format
index 693a3275606f2ab4c25e7647c5606ac42e88139d..6e4d305ac8ac6fa3d948d1bd7c1b1853248a0143 100644 (file)
                adc: adc@126C0000 {
                        compatible = "samsung,exynos3250-adc",
                                     "samsung,exynos-adc-v2";
-                       reg = <0x126C0000 0x100>, <0x10020718 0x4>;
+                       reg = <0x126C0000 0x100>;
                        interrupts = <0 137 0>;
                        clock-names = "adc", "sclk";
                        clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
                        #io-channel-cells = <1>;
                        io-channel-ranges;
+                       samsung,syscon-phandle = <&pmu_system_controller>;
                        status = "disabled";
                };
 
index 861bb919f6d391ea44f097565eb0d36781d1a20a..9ee77d3c4e036a4eab8fb3784dd83fd970303176 100644 (file)
 
        adc: adc@126C0000 {
                compatible = "samsung,exynos-adc-v1";
-               reg = <0x126C0000 0x100>, <0x10020718 0x4>;
+               reg = <0x126C0000 0x100>;
                interrupt-parent = <&combiner>;
                interrupts = <10 3>;
                clocks = <&clock CLK_TSADC>;
                clock-names = "adc";
                #io-channel-cells = <1>;
                io-channel-ranges;
+               samsung,syscon-phandle = <&pmu_system_controller>;
                status = "disabled";
        };
 
index f21b9aa00fbb214f4dee8b0b1980884f5411c70f..9bac5ede949d44e27f6db6fa126936c7f00c2b2f 100644 (file)
 
        adc: adc@12D10000 {
                compatible = "samsung,exynos-adc-v1";
-               reg = <0x12D10000 0x100>, <0x10040718 0x4>;
+               reg = <0x12D10000 0x100>;
                interrupts = <0 106 0>;
                clocks = <&clock CLK_ADC>;
                clock-names = "adc";
                #io-channel-cells = <1>;
                io-channel-ranges;
+               samsung,syscon-phandle = <&pmu_system_controller>;
                status = "disabled";
        };
 
index 8617a031cbc06bf670e42f167056fe6c061b0d63..aea870d1ac952dec4e05286a902a610ad0d15afb 100644 (file)
 
        adc: adc@12D10000 {
                compatible = "samsung,exynos-adc-v2";
-               reg = <0x12D10000 0x100>, <0x10040720 0x4>;
+               reg = <0x12D10000 0x100>;
                interrupts = <0 106 0>;
                clocks = <&clock CLK_TSADC>;
                clock-names = "adc";
                #io-channel-cells = <1>;
                io-channel-ranges;
+               samsung,syscon-phandle = <&pmu_system_controller>;
                status = "disabled";
        };
 
index c3877630b2e4cfa0fdf652183d9388183541a83a..fa964603430501b4cb1a4b73003a043fd16a7b34 100644 (file)
@@ -33,8 +33,7 @@ static const struct st_sensors_platform_data default_accel_pdata = {
        .drdy_int_pin = 1,
 };
 
-int st_accel_common_probe(struct iio_dev *indio_dev,
-                                       struct st_sensors_platform_data *pdata);
+int st_accel_common_probe(struct iio_dev *indio_dev);
 void st_accel_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
index 087864854c613e02cf1c58bdfb75c6650d0bcabc..53f32629283a0d06d3e22d20a91c25b51bd877a2 100644 (file)
@@ -161,7 +161,7 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(3)
 };
 
-static const struct st_sensors st_accel_sensors[] = {
+static const struct st_sensor_settings st_accel_sensors_settings[] = {
        {
                .wai = ST_ACCEL_1_WAI_EXP,
                .sensors_supported = {
@@ -457,8 +457,7 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
 #define ST_ACCEL_TRIGGER_OPS NULL
 #endif
 
-int st_accel_common_probe(struct iio_dev *indio_dev,
-                               struct st_sensors_platform_data *plat_data)
+int st_accel_common_probe(struct iio_dev *indio_dev)
 {
        struct st_sensor_data *adata = iio_priv(indio_dev);
        int irq = adata->get_irq_data_ready(indio_dev);
@@ -470,24 +469,25 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
        st_sensors_power_enable(indio_dev);
 
        err = st_sensors_check_device_support(indio_dev,
-                               ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
+                                       ARRAY_SIZE(st_accel_sensors_settings),
+                                       st_accel_sensors_settings);
        if (err < 0)
                return err;
 
        adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
-       adata->multiread_bit = adata->sensor->multi_read_bit;
-       indio_dev->channels = adata->sensor->ch;
+       adata->multiread_bit = adata->sensor_settings->multi_read_bit;
+       indio_dev->channels = adata->sensor_settings->ch;
        indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
 
        adata->current_fullscale = (struct st_sensor_fullscale_avl *)
-                                               &adata->sensor->fs.fs_avl[0];
-       adata->odr = adata->sensor->odr.odr_avl[0].hz;
+                                       &adata->sensor_settings->fs.fs_avl[0];
+       adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
 
-       if (!plat_data)
-               plat_data =
+       if (!adata->dev->platform_data)
+               adata->dev->platform_data =
                        (struct st_sensors_platform_data *)&default_accel_pdata;
 
-       err = st_sensors_init_sensor(indio_dev, plat_data);
+       err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
        if (err < 0)
                return err;
 
index 7164aeff3ab13ca14325585b12967b51c44bafa3..c7246bdd30b9532b2d4a8eea6910f532666731b5 100644 (file)
@@ -79,12 +79,11 @@ static int st_accel_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        adata = iio_priv(indio_dev);
-       adata->dev = &client->dev;
        st_sensors_of_i2c_probe(client, st_accel_of_match);
 
        st_sensors_i2c_configure(indio_dev, client, adata);
 
-       err = st_accel_common_probe(indio_dev, client->dev.platform_data);
+       err = st_accel_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index 195639646e34261305de590f6c0cccd0bd898a85..12ec29389e4ba15c794d3aaa74df3c5c917d3cee 100644 (file)
@@ -29,11 +29,10 @@ static int st_accel_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        adata = iio_priv(indio_dev);
-       adata->dev = &spi->dev;
 
        st_sensors_spi_configure(indio_dev, spi, adata);
 
-       err = st_accel_common_probe(indio_dev, spi->dev.platform_data);
+       err = st_accel_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index 88bdc8f612e2ccf299550fa8367fb2ad251b29b1..d0924f3cfa25eca0812fbac395052ceaa13a8d3e 100644 (file)
@@ -206,6 +206,20 @@ config NAU7802
          To compile this driver as a module, choose M here: the
          module will be called nau7802.
 
+config QCOM_SPMI_IADC
+       tristate "Qualcomm SPMI PMIC current ADC"
+       depends on SPMI
+       select REGMAP_SPMI
+       help
+         This is the IIO Current ADC driver for Qualcomm QPNP IADC Chip.
+
+         The driver supports single mode operation to read from one of two
+         channels (external or internal). Hardware have additional
+         channels internally used for gain and offset calibration.
+
+         To compile this driver as a module, choose M here: the module will
+         be called qcom-spmi-iadc.
+
 config ROCKCHIP_SARADC
        tristate "Rockchip SARADC driver"
        depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
index cb88a6a23b8fde707a9bd941b689132ddd4a4f1c..c06718b9d8ce223d30db6cb3872cbd5c595db7b9 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
+obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
index 43620fd4c66a73169b0ac1e34d42b1aa12fd060f..3a2dbb3b492635cbd866eace29c9fa1f2f762844 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/machine.h>
 #include <linux/iio/driver.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 /* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
 #define ADC_V1_CON(x)          ((x) + 0x00)
 
 #define EXYNOS_ADC_TIMEOUT     (msecs_to_jiffies(100))
 
+#define EXYNOS_ADCV1_PHY_OFFSET        0x0718
+#define EXYNOS_ADCV2_PHY_OFFSET        0x0720
+
 struct exynos_adc {
        struct exynos_adc_data  *data;
        struct device           *dev;
        void __iomem            *regs;
-       void __iomem            *enable_reg;
+       struct regmap           *pmu_map;
        struct clk              *clk;
        struct clk              *sclk;
        unsigned int            irq;
@@ -110,6 +115,7 @@ struct exynos_adc_data {
        int num_channels;
        bool needs_sclk;
        bool needs_adc_phy;
+       int phy_offset;
        u32 mask;
 
        void (*init_hw)(struct exynos_adc *info);
@@ -183,7 +189,7 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info)
        u32 con1;
 
        if (info->data->needs_adc_phy)
-               writel(1, info->enable_reg);
+               regmap_write(info->pmu_map, info->data->phy_offset, 1);
 
        /* set default prescaler values and Enable prescaler */
        con1 =  ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
@@ -198,7 +204,7 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
        u32 con;
 
        if (info->data->needs_adc_phy)
-               writel(0, info->enable_reg);
+               regmap_write(info->pmu_map, info->data->phy_offset, 0);
 
        con = readl(ADC_V1_CON(info->regs));
        con |= ADC_V1_CON_STANDBY;
@@ -225,6 +231,7 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
        .num_channels   = MAX_ADC_V1_CHANNELS,
        .mask           = ADC_DATX_MASK,        /* 12 bit ADC resolution */
        .needs_adc_phy  = true,
+       .phy_offset     = EXYNOS_ADCV1_PHY_OFFSET,
 
        .init_hw        = exynos_adc_v1_init_hw,
        .exit_hw        = exynos_adc_v1_exit_hw,
@@ -314,7 +321,7 @@ static void exynos_adc_v2_init_hw(struct exynos_adc *info)
        u32 con1, con2;
 
        if (info->data->needs_adc_phy)
-               writel(1, info->enable_reg);
+               regmap_write(info->pmu_map, info->data->phy_offset, 1);
 
        con1 = ADC_V2_CON1_SOFT_RESET;
        writel(con1, ADC_V2_CON1(info->regs));
@@ -332,7 +339,7 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
        u32 con;
 
        if (info->data->needs_adc_phy)
-               writel(0, info->enable_reg);
+               regmap_write(info->pmu_map, info->data->phy_offset, 0);
 
        con = readl(ADC_V2_CON1(info->regs));
        con &= ~ADC_CON_EN_START;
@@ -362,6 +369,7 @@ static const struct exynos_adc_data exynos_adc_v2_data = {
        .num_channels   = MAX_ADC_V2_CHANNELS,
        .mask           = ADC_DATX_MASK, /* 12 bit ADC resolution */
        .needs_adc_phy  = true,
+       .phy_offset     = EXYNOS_ADCV2_PHY_OFFSET,
 
        .init_hw        = exynos_adc_v2_init_hw,
        .exit_hw        = exynos_adc_v2_exit_hw,
@@ -374,6 +382,7 @@ static const struct exynos_adc_data exynos3250_adc_data = {
        .mask           = ADC_DATX_MASK, /* 12 bit ADC resolution */
        .needs_sclk     = true,
        .needs_adc_phy  = true,
+       .phy_offset     = EXYNOS_ADCV1_PHY_OFFSET,
 
        .init_hw        = exynos_adc_v2_init_hw,
        .exit_hw        = exynos_adc_v2_exit_hw,
@@ -381,6 +390,35 @@ static const struct exynos_adc_data exynos3250_adc_data = {
        .start_conv     = exynos_adc_v2_start_conv,
 };
 
+static void exynos_adc_exynos7_init_hw(struct exynos_adc *info)
+{
+       u32 con1, con2;
+
+       if (info->data->needs_adc_phy)
+               regmap_write(info->pmu_map, info->data->phy_offset, 1);
+
+       con1 = ADC_V2_CON1_SOFT_RESET;
+       writel(con1, ADC_V2_CON1(info->regs));
+
+       con2 = readl(ADC_V2_CON2(info->regs));
+       con2 &= ~ADC_V2_CON2_C_TIME(7);
+       con2 |= ADC_V2_CON2_C_TIME(0);
+       writel(con2, ADC_V2_CON2(info->regs));
+
+       /* Enable interrupts */
+       writel(1, ADC_V2_INT_EN(info->regs));
+}
+
+static const struct exynos_adc_data exynos7_adc_data = {
+       .num_channels   = MAX_ADC_V1_CHANNELS,
+       .mask           = ADC_DATX_MASK, /* 12 bit ADC resolution */
+
+       .init_hw        = exynos_adc_exynos7_init_hw,
+       .exit_hw        = exynos_adc_v2_exit_hw,
+       .clear_irq      = exynos_adc_v2_clear_irq,
+       .start_conv     = exynos_adc_v2_start_conv,
+};
+
 static const struct of_device_id exynos_adc_match[] = {
        {
                .compatible = "samsung,s3c2410-adc",
@@ -406,6 +444,9 @@ static const struct of_device_id exynos_adc_match[] = {
        }, {
                .compatible = "samsung,exynos3250-adc",
                .data = &exynos3250_adc_data,
+       }, {
+               .compatible = "samsung,exynos7-adc",
+               .data = &exynos7_adc_data,
        },
        {},
 };
@@ -558,10 +599,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
 
        if (info->data->needs_adc_phy) {
-               mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
-               if (IS_ERR(info->enable_reg))
-                       return PTR_ERR(info->enable_reg);
+               info->pmu_map = syscon_regmap_lookup_by_phandle(
+                                       pdev->dev.of_node,
+                                       "samsung,syscon-phandle");
+               if (IS_ERR(info->pmu_map)) {
+                       dev_err(&pdev->dev, "syscon regmap lookup failed.\n");
+                       return PTR_ERR(info->pmu_map);
+               }
        }
 
        irq = platform_get_irq(pdev, 0);
index 28a086e48776255b3ba8889111dbb73203b5005e..efbfd12a4bfdd9f764732d976a2650719408552c 100644 (file)
@@ -1,9 +1,30 @@
 /*
  * Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com>
+ * Copyright (C) 2014 Rose Technology
+ *        Allan Bendorff Jensen <abj@rosetechnology.dk>
+ *        Soren Andersen <san@rosetechnology.dk>
+ *
+ * Driver for following ADC chips from Microchip Technology's:
+ * 10 Bit converter
+ * MCP3001
+ * MCP3002
+ * MCP3004
+ * MCP3008
+ * ------------
+ * 12 bit converter
+ * MCP3201
+ * MCP3202
+ * MCP3204
+ * MCP3208
+ * ------------
  *
- * Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips.
  * Datasheet can be found here:
- * http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf  mcp3001
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf  mcp3002
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf  mcp3004/08
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf  mcp3201
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf  mcp3202
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf  mcp3204/08
  *
  * 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
  */
 
 #include <linux/err.h>
+#include <linux/delay.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 #include <linux/iio/iio.h>
 #include <linux/regulator/consumer.h>
 
-#define MCP_SINGLE_ENDED       (1 << 3)
-#define MCP_START_BIT          (1 << 4)
-
 enum {
+       mcp3001,
+       mcp3002,
+       mcp3004,
+       mcp3008,
+       mcp3201,
+       mcp3202,
        mcp3204,
        mcp3208,
 };
 
+struct mcp320x_chip_info {
+       const struct iio_chan_spec *channels;
+       unsigned int num_channels;
+       unsigned int resolution;
+};
+
 struct mcp320x {
        struct spi_device *spi;
        struct spi_message msg;
@@ -34,19 +65,69 @@ struct mcp320x {
 
        struct regulator *reg;
        struct mutex lock;
+       const struct mcp320x_chip_info *chip_info;
 };
 
-static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg)
+static int mcp320x_channel_to_tx_data(int device_index,
+                       const unsigned int channel, bool differential)
+{
+       int start_bit = 1;
+
+       switch (device_index) {
+       case mcp3001:
+       case mcp3201:
+               return 0;
+       case mcp3002:
+       case mcp3202:
+               return ((start_bit << 4) | (!differential << 3) |
+                                                       (channel << 2));
+       case mcp3004:
+       case mcp3204:
+       case mcp3008:
+       case mcp3208:
+               return ((start_bit << 6) | (!differential << 5) |
+                                                       (channel << 2));
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
+                                 bool differential, int device_index)
 {
        int ret;
 
-       adc->tx_buf = msg;
-       ret = spi_sync(adc->spi, &adc->msg);
-       if (ret < 0)
-               return ret;
+       adc->rx_buf[0] = 0;
+       adc->rx_buf[1] = 0;
+       adc->tx_buf = mcp320x_channel_to_tx_data(device_index,
+                                               channel, differential);
+
+       if (device_index != mcp3001 && device_index != mcp3201) {
+               ret = spi_sync(adc->spi, &adc->msg);
+               if (ret < 0)
+                       return ret;
+       } else {
+               ret = spi_read(adc->spi, &adc->rx_buf, sizeof(adc->rx_buf));
+               if (ret < 0)
+                       return ret;
+       }
 
-       return ((adc->rx_buf[0] & 0x3f) << 6)  |
-               (adc->rx_buf[1] >> 2);
+       switch (device_index) {
+       case mcp3001:
+               return (adc->rx_buf[0] << 5 | adc->rx_buf[1] >> 3);
+       case mcp3002:
+       case mcp3004:
+       case mcp3008:
+               return (adc->rx_buf[0] << 2 | adc->rx_buf[1] >> 6);
+       case mcp3201:
+               return (adc->rx_buf[0] << 7 | adc->rx_buf[1] >> 1);
+       case mcp3202:
+       case mcp3204:
+       case mcp3208:
+               return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
+       default:
+               return -EINVAL;
+       }
 }
 
 static int mcp320x_read_raw(struct iio_dev *indio_dev,
@@ -55,18 +136,17 @@ static int mcp320x_read_raw(struct iio_dev *indio_dev,
 {
        struct mcp320x *adc = iio_priv(indio_dev);
        int ret = -EINVAL;
+       int device_index = 0;
 
        mutex_lock(&adc->lock);
 
+       device_index = spi_get_device_id(adc->spi)->driver_data;
+
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               if (channel->differential)
-                       ret = mcp320x_adc_conversion(adc,
-                               MCP_START_BIT | channel->address);
-               else
-                       ret = mcp320x_adc_conversion(adc,
-                               MCP_START_BIT | MCP_SINGLE_ENDED |
-                               channel->address);
+               ret = mcp320x_adc_conversion(adc, channel->address,
+                       channel->differential, device_index);
+
                if (ret < 0)
                        goto out;
 
@@ -75,18 +155,15 @@ static int mcp320x_read_raw(struct iio_dev *indio_dev,
                break;
 
        case IIO_CHAN_INFO_SCALE:
-               /* Digital output code = (4096 * Vin) / Vref */
                ret = regulator_get_voltage(adc->reg);
                if (ret < 0)
                        goto out;
 
+               /* convert regulator output voltage to mV */
                *val = ret / 1000;
-               *val2 = 12;
+               *val2 = adc->chip_info->resolution;
                ret = IIO_VAL_FRACTIONAL_LOG2;
                break;
-
-       default:
-               break;
        }
 
 out:
@@ -117,6 +194,16 @@ out:
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
        }
 
+static const struct iio_chan_spec mcp3201_channels[] = {
+       MCP320X_VOLTAGE_CHANNEL_DIFF(0),
+};
+
+static const struct iio_chan_spec mcp3202_channels[] = {
+       MCP320X_VOLTAGE_CHANNEL(0),
+       MCP320X_VOLTAGE_CHANNEL(1),
+       MCP320X_VOLTAGE_CHANNEL_DIFF(0),
+};
+
 static const struct iio_chan_spec mcp3204_channels[] = {
        MCP320X_VOLTAGE_CHANNEL(0),
        MCP320X_VOLTAGE_CHANNEL(1),
@@ -146,19 +233,46 @@ static const struct iio_info mcp320x_info = {
        .driver_module = THIS_MODULE,
 };
 
-struct mcp3208_chip_info {
-       const struct iio_chan_spec *channels;
-       unsigned int num_channels;
-};
-
-static const struct mcp3208_chip_info mcp3208_chip_infos[] = {
+static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
+       [mcp3001] = {
+               .channels = mcp3201_channels,
+               .num_channels = ARRAY_SIZE(mcp3201_channels),
+               .resolution = 10
+       },
+       [mcp3002] = {
+               .channels = mcp3202_channels,
+               .num_channels = ARRAY_SIZE(mcp3202_channels),
+               .resolution = 10
+       },
+       [mcp3004] = {
+               .channels = mcp3204_channels,
+               .num_channels = ARRAY_SIZE(mcp3204_channels),
+               .resolution = 10
+       },
+       [mcp3008] = {
+               .channels = mcp3208_channels,
+               .num_channels = ARRAY_SIZE(mcp3208_channels),
+               .resolution = 10
+       },
+       [mcp3201] = {
+               .channels = mcp3201_channels,
+               .num_channels = ARRAY_SIZE(mcp3201_channels),
+               .resolution = 12
+       },
+       [mcp3202] = {
+               .channels = mcp3202_channels,
+               .num_channels = ARRAY_SIZE(mcp3202_channels),
+               .resolution = 12
+       },
        [mcp3204] = {
                .channels = mcp3204_channels,
-               .num_channels = ARRAY_SIZE(mcp3204_channels)
+               .num_channels = ARRAY_SIZE(mcp3204_channels),
+               .resolution = 12
        },
        [mcp3208] = {
                .channels = mcp3208_channels,
-               .num_channels = ARRAY_SIZE(mcp3208_channels)
+               .num_channels = ARRAY_SIZE(mcp3208_channels),
+               .resolution = 12
        },
 };
 
@@ -166,7 +280,7 @@ static int mcp320x_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
        struct mcp320x *adc;
-       const struct mcp3208_chip_info *chip_info;
+       const struct mcp320x_chip_info *chip_info;
        int ret;
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
@@ -181,7 +295,7 @@ static int mcp320x_probe(struct spi_device *spi)
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &mcp320x_info;
 
-       chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data];
+       chip_info = &mcp320x_chip_infos[spi_get_device_id(spi)->driver_data];
        indio_dev->channels = chip_info->channels;
        indio_dev->num_channels = chip_info->num_channels;
 
@@ -226,7 +340,45 @@ static int mcp320x_remove(struct spi_device *spi)
        return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id mcp320x_dt_ids[] = {
+       {
+               .compatible = "mcp3001",
+               .data = &mcp320x_chip_infos[mcp3001],
+       }, {
+               .compatible = "mcp3002",
+               .data = &mcp320x_chip_infos[mcp3002],
+       }, {
+               .compatible = "mcp3004",
+               .data = &mcp320x_chip_infos[mcp3004],
+       }, {
+               .compatible = "mcp3008",
+               .data = &mcp320x_chip_infos[mcp3008],
+       }, {
+               .compatible = "mcp3201",
+               .data = &mcp320x_chip_infos[mcp3201],
+       }, {
+               .compatible = "mcp3202",
+               .data = &mcp320x_chip_infos[mcp3202],
+       }, {
+               .compatible = "mcp3204",
+               .data = &mcp320x_chip_infos[mcp3204],
+       }, {
+               .compatible = "mcp3208",
+               .data = &mcp320x_chip_infos[mcp3208],
+       }, {
+       }
+};
+MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
+#endif
+
 static const struct spi_device_id mcp320x_id[] = {
+       { "mcp3001", mcp3001 },
+       { "mcp3002", mcp3002 },
+       { "mcp3004", mcp3004 },
+       { "mcp3008", mcp3008 },
+       { "mcp3201", mcp3201 },
+       { "mcp3202", mcp3202 },
        { "mcp3204", mcp3204 },
        { "mcp3208", mcp3208 },
        { }
@@ -245,5 +397,5 @@ static struct spi_driver mcp320x_driver = {
 module_spi_driver(mcp320x_driver);
 
 MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
-MODULE_DESCRIPTION("Microchip Technology MCP3204/08");
+MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
new file mode 100644 (file)
index 0000000..b9666f2
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* IADC register and bit definition */
+#define IADC_REVISION2                         0x1
+#define IADC_REVISION2_SUPPORTED_IADC          1
+
+#define IADC_PERPH_TYPE                                0x4
+#define IADC_PERPH_TYPE_ADC                    8
+
+#define IADC_PERPH_SUBTYPE                     0x5
+#define IADC_PERPH_SUBTYPE_IADC                        3
+
+#define IADC_STATUS1                           0x8
+#define IADC_STATUS1_OP_MODE                   4
+#define IADC_STATUS1_REQ_STS                   BIT(1)
+#define IADC_STATUS1_EOC                       BIT(0)
+#define IADC_STATUS1_REQ_STS_EOC_MASK          0x3
+
+#define IADC_MODE_CTL                          0x40
+#define IADC_OP_MODE_SHIFT                     3
+#define IADC_OP_MODE_NORMAL                    0
+#define IADC_TRIM_EN                           BIT(0)
+
+#define IADC_EN_CTL1                           0x46
+#define IADC_EN_CTL1_SET                       BIT(7)
+
+#define IADC_CH_SEL_CTL                                0x48
+
+#define IADC_DIG_PARAM                         0x50
+#define IADC_DIG_DEC_RATIO_SEL_SHIFT           2
+
+#define IADC_HW_SETTLE_DELAY                   0x51
+
+#define IADC_CONV_REQ                          0x52
+#define IADC_CONV_REQ_SET                      BIT(7)
+
+#define IADC_FAST_AVG_CTL                      0x5a
+#define IADC_FAST_AVG_EN                       0x5b
+#define IADC_FAST_AVG_EN_SET                   BIT(7)
+
+#define IADC_PERH_RESET_CTL3                   0xda
+#define IADC_FOLLOW_WARM_RB                    BIT(2)
+
+#define IADC_DATA                              0x60    /* 16 bits */
+
+#define IADC_SEC_ACCESS                                0xd0
+#define IADC_SEC_ACCESS_DATA                   0xa5
+
+#define IADC_NOMINAL_RSENSE                    0xf4
+#define IADC_NOMINAL_RSENSE_SIGN_MASK          BIT(7)
+
+#define IADC_REF_GAIN_MICRO_VOLTS              17857
+
+#define IADC_INT_RSENSE_DEVIATION              15625   /* nano Ohms per bit */
+
+#define IADC_INT_RSENSE_IDEAL_VALUE            10000   /* micro Ohms */
+#define IADC_INT_RSENSE_DEFAULT_VALUE          7800    /* micro Ohms */
+#define IADC_INT_RSENSE_DEFAULT_GF             9000    /* micro Ohms */
+#define IADC_INT_RSENSE_DEFAULT_SMIC           9700    /* micro Ohms */
+
+#define IADC_CONV_TIME_MIN_US                  2000
+#define IADC_CONV_TIME_MAX_US                  2100
+
+#define IADC_DEF_PRESCALING                    0 /* 1:1 */
+#define IADC_DEF_DECIMATION                    0 /* 512 */
+#define IADC_DEF_HW_SETTLE_TIME                        0 /* 0 us */
+#define IADC_DEF_AVG_SAMPLES                   0 /* 1 sample */
+
+/* IADC channel list */
+#define IADC_INT_RSENSE                                0
+#define IADC_EXT_RSENSE                                1
+#define IADC_GAIN_17P857MV                     3
+#define IADC_EXT_OFFSET_CSP_CSN                        5
+#define IADC_INT_OFFSET_CSP2_CSN2              6
+
+/**
+ * struct iadc_chip - IADC Current ADC device structure.
+ * @regmap: regmap for register read/write.
+ * @dev: This device pointer.
+ * @base: base offset for the ADC peripheral.
+ * @rsense: Values of the internal and external sense resister in micro Ohms.
+ * @poll_eoc: Poll for end of conversion instead of waiting for IRQ.
+ * @offset: Raw offset values for the internal and external channels.
+ * @gain: Raw gain of the channels.
+ * @lock: ADC lock for access to the peripheral.
+ * @complete: ADC notification after end of conversion interrupt is received.
+ */
+struct iadc_chip {
+       struct regmap   *regmap;
+       struct device   *dev;
+       u16             base;
+       bool            poll_eoc;
+       u32             rsense[2];
+       u16             offset[2];
+       u16             gain;
+       struct mutex    lock;
+       struct completion complete;
+};
+
+static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(iadc->regmap, iadc->base + offset, &val);
+       if (ret < 0)
+               return ret;
+
+       *data = val;
+       return 0;
+}
+
+static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data)
+{
+       return regmap_write(iadc->regmap, iadc->base + offset, data);
+}
+
+static int iadc_reset(struct iadc_chip *iadc)
+{
+       u8 data;
+       int ret;
+
+       ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
+       if (ret < 0)
+               return ret;
+
+       ret = iadc_read(iadc, IADC_PERH_RESET_CTL3, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
+       if (ret < 0)
+               return ret;
+
+       data |= IADC_FOLLOW_WARM_RB;
+
+       return iadc_write(iadc, IADC_PERH_RESET_CTL3, data);
+}
+
+static int iadc_set_state(struct iadc_chip *iadc, bool state)
+{
+       return iadc_write(iadc, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0);
+}
+
+static void iadc_status_show(struct iadc_chip *iadc)
+{
+       u8 mode, sta1, chan, dig, en, req;
+       int ret;
+
+       ret = iadc_read(iadc, IADC_MODE_CTL, &mode);
+       if (ret < 0)
+               return;
+
+       ret = iadc_read(iadc, IADC_DIG_PARAM, &dig);
+       if (ret < 0)
+               return;
+
+       ret = iadc_read(iadc, IADC_CH_SEL_CTL, &chan);
+       if (ret < 0)
+               return;
+
+       ret = iadc_read(iadc, IADC_CONV_REQ, &req);
+       if (ret < 0)
+               return;
+
+       ret = iadc_read(iadc, IADC_STATUS1, &sta1);
+       if (ret < 0)
+               return;
+
+       ret = iadc_read(iadc, IADC_EN_CTL1, &en);
+       if (ret < 0)
+               return;
+
+       dev_err(iadc->dev,
+               "mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n",
+               mode, en, chan, dig, req, sta1);
+}
+
+static int iadc_configure(struct iadc_chip *iadc, int channel)
+{
+       u8 decim, mode;
+       int ret;
+
+       /* Mode selection */
+       mode = (IADC_OP_MODE_NORMAL << IADC_OP_MODE_SHIFT) | IADC_TRIM_EN;
+       ret = iadc_write(iadc, IADC_MODE_CTL, mode);
+       if (ret < 0)
+               return ret;
+
+       /* Channel selection */
+       ret = iadc_write(iadc, IADC_CH_SEL_CTL, channel);
+       if (ret < 0)
+               return ret;
+
+       /* Digital parameter setup */
+       decim = IADC_DEF_DECIMATION << IADC_DIG_DEC_RATIO_SEL_SHIFT;
+       ret = iadc_write(iadc, IADC_DIG_PARAM, decim);
+       if (ret < 0)
+               return ret;
+
+       /* HW settle time delay */
+       ret = iadc_write(iadc, IADC_HW_SETTLE_DELAY, IADC_DEF_HW_SETTLE_TIME);
+       if (ret < 0)
+               return ret;
+
+       ret = iadc_write(iadc, IADC_FAST_AVG_CTL, IADC_DEF_AVG_SAMPLES);
+       if (ret < 0)
+               return ret;
+
+       if (IADC_DEF_AVG_SAMPLES)
+               ret = iadc_write(iadc, IADC_FAST_AVG_EN, IADC_FAST_AVG_EN_SET);
+       else
+               ret = iadc_write(iadc, IADC_FAST_AVG_EN, 0);
+
+       if (ret < 0)
+               return ret;
+
+       if (!iadc->poll_eoc)
+               reinit_completion(&iadc->complete);
+
+       ret = iadc_set_state(iadc, true);
+       if (ret < 0)
+               return ret;
+
+       /* Request conversion */
+       return iadc_write(iadc, IADC_CONV_REQ, IADC_CONV_REQ_SET);
+}
+
+static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us)
+{
+       unsigned int count, retry;
+       int ret;
+       u8 sta1;
+
+       retry = interval_us / IADC_CONV_TIME_MIN_US;
+
+       for (count = 0; count < retry; count++) {
+               ret = iadc_read(iadc, IADC_STATUS1, &sta1);
+               if (ret < 0)
+                       return ret;
+
+               sta1 &= IADC_STATUS1_REQ_STS_EOC_MASK;
+               if (sta1 == IADC_STATUS1_EOC)
+                       return 0;
+
+               usleep_range(IADC_CONV_TIME_MIN_US, IADC_CONV_TIME_MAX_US);
+       }
+
+       iadc_status_show(iadc);
+
+       return -ETIMEDOUT;
+}
+
+static int iadc_read_result(struct iadc_chip *iadc, u16 *data)
+{
+       return regmap_bulk_read(iadc->regmap, iadc->base + IADC_DATA, data, 2);
+}
+
+static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
+{
+       unsigned int wait;
+       int ret;
+
+       ret = iadc_configure(iadc, chan);
+       if (ret < 0)
+               goto exit;
+
+       wait = BIT(IADC_DEF_AVG_SAMPLES) * IADC_CONV_TIME_MIN_US * 2;
+
+       if (iadc->poll_eoc) {
+               ret = iadc_poll_wait_eoc(iadc, wait);
+       } else {
+               ret = wait_for_completion_timeout(&iadc->complete, wait);
+               if (!ret)
+                       ret = -ETIMEDOUT;
+               else
+                       /* double check conversion status */
+                       ret = iadc_poll_wait_eoc(iadc, IADC_CONV_TIME_MIN_US);
+       }
+
+       if (!ret)
+               ret = iadc_read_result(iadc, data);
+exit:
+       iadc_set_state(iadc, false);
+       if (ret < 0)
+               dev_err(iadc->dev, "conversion failed\n");
+
+       return ret;
+}
+
+static int iadc_read_raw(struct iio_dev *indio_dev,
+                        struct iio_chan_spec const *chan,
+                        int *val, int *val2, long mask)
+{
+       struct iadc_chip *iadc = iio_priv(indio_dev);
+       s32 isense_ua, vsense_uv;
+       u16 adc_raw, vsense_raw;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&iadc->lock);
+               ret = iadc_do_conversion(iadc, chan->channel, &adc_raw);
+               mutex_unlock(&iadc->lock);
+               if (ret < 0)
+                       return ret;
+
+               vsense_raw = adc_raw - iadc->offset[chan->channel];
+
+               vsense_uv = vsense_raw * IADC_REF_GAIN_MICRO_VOLTS;
+               vsense_uv /= (s32)iadc->gain - iadc->offset[chan->channel];
+
+               isense_ua = vsense_uv / iadc->rsense[chan->channel];
+
+               dev_dbg(iadc->dev, "off %d gain %d adc %d %duV I %duA\n",
+                       iadc->offset[chan->channel], iadc->gain,
+                       adc_raw, vsense_uv, isense_ua);
+
+               *val = isense_ua;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = 1000;
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_info iadc_info = {
+       .read_raw = iadc_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static irqreturn_t iadc_isr(int irq, void *dev_id)
+{
+       struct iadc_chip *iadc = dev_id;
+
+       complete(&iadc->complete);
+
+       return IRQ_HANDLED;
+}
+
+static int iadc_update_offset(struct iadc_chip *iadc)
+{
+       int ret;
+
+       ret = iadc_do_conversion(iadc, IADC_GAIN_17P857MV, &iadc->gain);
+       if (ret < 0)
+               return ret;
+
+       ret = iadc_do_conversion(iadc, IADC_INT_OFFSET_CSP2_CSN2,
+                                &iadc->offset[IADC_INT_RSENSE]);
+       if (ret < 0)
+               return ret;
+
+       if (iadc->gain == iadc->offset[IADC_INT_RSENSE]) {
+               dev_err(iadc->dev, "error: internal offset == gain %d\n",
+                       iadc->gain);
+               return -EINVAL;
+       }
+
+       ret = iadc_do_conversion(iadc, IADC_EXT_OFFSET_CSP_CSN,
+                                &iadc->offset[IADC_EXT_RSENSE]);
+       if (ret < 0)
+               return ret;
+
+       if (iadc->gain == iadc->offset[IADC_EXT_RSENSE]) {
+               dev_err(iadc->dev, "error: external offset == gain %d\n",
+                       iadc->gain);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int iadc_version_check(struct iadc_chip *iadc)
+{
+       u8 val;
+       int ret;
+
+       ret = iadc_read(iadc, IADC_PERPH_TYPE, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val < IADC_PERPH_TYPE_ADC) {
+               dev_err(iadc->dev, "%d is not ADC\n", val);
+               return -EINVAL;
+       }
+
+       ret = iadc_read(iadc, IADC_PERPH_SUBTYPE, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val < IADC_PERPH_SUBTYPE_IADC) {
+               dev_err(iadc->dev, "%d is not IADC\n", val);
+               return -EINVAL;
+       }
+
+       ret = iadc_read(iadc, IADC_REVISION2, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val < IADC_REVISION2_SUPPORTED_IADC) {
+               dev_err(iadc->dev, "revision %d not supported\n", val);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int iadc_rsense_read(struct iadc_chip *iadc, struct device_node *node)
+{
+       int ret, sign, int_sense;
+       u8 deviation;
+
+       ret = of_property_read_u32(node, "qcom,external-resistor-micro-ohms",
+                                  &iadc->rsense[IADC_EXT_RSENSE]);
+       if (ret < 0)
+               iadc->rsense[IADC_EXT_RSENSE] = IADC_INT_RSENSE_IDEAL_VALUE;
+
+       if (!iadc->rsense[IADC_EXT_RSENSE]) {
+               dev_err(iadc->dev, "external resistor can't be zero Ohms");
+               return -EINVAL;
+       }
+
+       ret = iadc_read(iadc, IADC_NOMINAL_RSENSE, &deviation);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Deviation value stored is an offset from 10 mili Ohms, bit 7 is
+        * the sign, the remaining bits have an LSB of 15625 nano Ohms.
+        */
+       sign = (deviation & IADC_NOMINAL_RSENSE_SIGN_MASK) ? -1 : 1;
+
+       deviation &= ~IADC_NOMINAL_RSENSE_SIGN_MASK;
+
+       /* Scale it to nono Ohms */
+       int_sense = IADC_INT_RSENSE_IDEAL_VALUE * 1000;
+       int_sense += sign * deviation * IADC_INT_RSENSE_DEVIATION;
+       int_sense /= 1000; /* micro Ohms */
+
+       iadc->rsense[IADC_INT_RSENSE] = int_sense;
+       return 0;
+}
+
+static const struct iio_chan_spec iadc_channels[] = {
+       {
+               .type = IIO_CURRENT,
+               .datasheet_name = "INTERNAL_RSENSE",
+               .channel = 0,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .indexed = 1,
+       },
+       {
+               .type = IIO_CURRENT,
+               .datasheet_name = "EXTERNAL_RSENSE",
+               .channel = 1,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .indexed = 1,
+       },
+};
+
+static int iadc_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct iio_dev *indio_dev;
+       struct iadc_chip *iadc;
+       int ret, irq_eoc;
+       u32 res;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*iadc));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       iadc = iio_priv(indio_dev);
+       iadc->dev = dev;
+
+       iadc->regmap = dev_get_regmap(dev->parent, NULL);
+       if (!iadc->regmap)
+               return -ENODEV;
+
+       init_completion(&iadc->complete);
+       mutex_init(&iadc->lock);
+
+       ret = of_property_read_u32(node, "reg", &res);
+       if (ret < 0)
+               return -ENODEV;
+
+       iadc->base = res;
+
+       ret = iadc_version_check(iadc);
+       if (ret < 0)
+               return -ENODEV;
+
+       ret = iadc_rsense_read(iadc, node);
+       if (ret < 0)
+               return -ENODEV;
+
+       dev_dbg(iadc->dev, "sense resistors %d and %d micro Ohm\n",
+               iadc->rsense[IADC_INT_RSENSE],
+               iadc->rsense[IADC_EXT_RSENSE]);
+
+       irq_eoc = platform_get_irq(pdev, 0);
+       if (irq_eoc == -EPROBE_DEFER)
+               return irq_eoc;
+
+       if (irq_eoc < 0)
+               iadc->poll_eoc = true;
+
+       ret = iadc_reset(iadc);
+       if (ret < 0) {
+               dev_err(dev, "reset failed\n");
+               return ret;
+       }
+
+       if (!iadc->poll_eoc) {
+               ret = devm_request_irq(dev, irq_eoc, iadc_isr, 0,
+                                       "spmi-iadc", iadc);
+               if (!ret)
+                       enable_irq_wake(irq_eoc);
+               else
+                       return ret;
+       } else {
+               device_init_wakeup(iadc->dev, 1);
+       }
+
+       ret = iadc_update_offset(iadc);
+       if (ret < 0) {
+               dev_err(dev, "failed offset calibration\n");
+               return ret;
+       }
+
+       indio_dev->dev.parent = dev;
+       indio_dev->dev.of_node = node;
+       indio_dev->name = pdev->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &iadc_info;
+       indio_dev->channels = iadc_channels;
+       indio_dev->num_channels = ARRAY_SIZE(iadc_channels);
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id iadc_match_table[] = {
+       { .compatible = "qcom,spmi-iadc" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, iadc_match_table);
+
+static struct platform_driver iadc_driver = {
+       .driver = {
+                  .name = "qcom-spmi-iadc",
+                  .of_match_table = iadc_match_table,
+       },
+       .probe = iadc_probe,
+};
+
+module_platform_driver(iadc_driver);
+
+MODULE_ALIAS("platform:qcom-spmi-iadc");
+MODULE_DESCRIPTION("Qualcomm SPMI PMIC current ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
index e074a0b03f284670ca708dad5c1b1a4aed1c315a..b546bc1a9c30019a76f54b209a7e4730499e7ff0 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/regulator/consumer.h>
 #include <linux/iio/iio.h>
 
 #define SARADC_DATA                    0x00
-#define SARADC_DATA_MASK               0x3ff
 
 #define SARADC_STAS                    0x04
 #define SARADC_STAS_BUSY               BIT(0)
 #define SARADC_DLY_PU_SOC              0x0c
 #define SARADC_DLY_PU_SOC_MASK         0x3f
 
-#define SARADC_BITS                    10
 #define SARADC_TIMEOUT                 msecs_to_jiffies(100)
 
+struct rockchip_saradc_data {
+       int                             num_bits;
+       const struct iio_chan_spec      *channels;
+       int                             num_channels;
+       unsigned long                   clk_rate;
+};
+
 struct rockchip_saradc {
        void __iomem            *regs;
        struct clk              *pclk;
        struct clk              *clk;
        struct completion       completion;
        struct regulator        *vref;
+       const struct rockchip_saradc_data *data;
        u16                     last_val;
 };
 
@@ -90,7 +97,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
                }
 
                *val = ret / 1000;
-               *val2 = SARADC_BITS;
+               *val2 = info->data->num_bits;
                return IIO_VAL_FRACTIONAL_LOG2;
        default:
                return -EINVAL;
@@ -103,7 +110,7 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
 
        /* Read value */
        info->last_val = readl_relaxed(info->regs + SARADC_DATA);
-       info->last_val &= SARADC_DATA_MASK;
+       info->last_val &= GENMASK(info->data->num_bits - 1, 0);
 
        /* Clear irq & power down adc */
        writel_relaxed(0, info->regs + SARADC_CTRL);
@@ -133,12 +140,44 @@ static const struct iio_chan_spec rockchip_saradc_iio_channels[] = {
        ADC_CHANNEL(2, "adc2"),
 };
 
+static const struct rockchip_saradc_data saradc_data = {
+       .num_bits = 10,
+       .channels = rockchip_saradc_iio_channels,
+       .num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels),
+       .clk_rate = 1000000,
+};
+
+static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = {
+       ADC_CHANNEL(0, "adc0"),
+       ADC_CHANNEL(1, "adc1"),
+};
+
+static const struct rockchip_saradc_data rk3066_tsadc_data = {
+       .num_bits = 12,
+       .channels = rockchip_rk3066_tsadc_iio_channels,
+       .num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels),
+       .clk_rate = 50000,
+};
+
+static const struct of_device_id rockchip_saradc_match[] = {
+       {
+               .compatible = "rockchip,saradc",
+               .data = &saradc_data,
+       }, {
+               .compatible = "rockchip,rk3066-tsadc",
+               .data = &rk3066_tsadc_data,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
+
 static int rockchip_saradc_probe(struct platform_device *pdev)
 {
        struct rockchip_saradc *info = NULL;
        struct device_node *np = pdev->dev.of_node;
        struct iio_dev *indio_dev = NULL;
        struct resource *mem;
+       const struct of_device_id *match;
        int ret;
        int irq;
 
@@ -152,6 +191,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        }
        info = iio_priv(indio_dev);
 
+       match = of_match_device(rockchip_saradc_match, &pdev->dev);
+       info->data = match->data;
+
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        info->regs = devm_ioremap_resource(&pdev->dev, mem);
        if (IS_ERR(info->regs))
@@ -192,10 +234,10 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        }
 
        /*
-        * Use a default of 1MHz for the converter clock.
+        * Use a default value for the converter clock.
         * This may become user-configurable in the future.
         */
-       ret = clk_set_rate(info->clk, 1000000);
+       ret = clk_set_rate(info->clk, info->data->clk_rate);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
                return ret;
@@ -227,8 +269,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        indio_dev->info = &rockchip_saradc_iio_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       indio_dev->channels = rockchip_saradc_iio_channels;
-       indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels);
+       indio_dev->channels = info->data->channels;
+       indio_dev->num_channels = info->data->num_channels;
 
        ret = iio_device_register(indio_dev);
        if (ret)
@@ -296,12 +338,6 @@ static int rockchip_saradc_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
                         rockchip_saradc_suspend, rockchip_saradc_resume);
 
-static const struct of_device_id rockchip_saradc_match[] = {
-       { .compatible = "rockchip,saradc" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
-
 static struct platform_driver rockchip_saradc_driver = {
        .probe          = rockchip_saradc_probe,
        .remove         = rockchip_saradc_remove,
index 4a10ae97dbf20a025a49c0af61908a93722fc60e..8ec353c01d98e02e7074df9d4d295ec19f772f09 100644 (file)
@@ -91,7 +91,7 @@
 #define VF610_ADC_CAL                  0x80
 
 /* Other field define */
-#define VF610_ADC_ADCHC(x)             ((x) & 0xF)
+#define VF610_ADC_ADCHC(x)             ((x) & 0x1F)
 #define VF610_ADC_AIEN                 (0x1 << 7)
 #define VF610_ADC_CONV_DISABLE         0x1F
 #define VF610_ADC_HS_COCO0             0x1
@@ -153,6 +153,12 @@ struct vf610_adc {
                                BIT(IIO_CHAN_INFO_SAMP_FREQ),   \
 }
 
+#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
+       .type = (_chan_type),   \
+       .channel = (_idx),              \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),     \
+}
+
 static const struct iio_chan_spec vf610_adc_iio_channels[] = {
        VF610_ADC_CHAN(0, IIO_VOLTAGE),
        VF610_ADC_CHAN(1, IIO_VOLTAGE),
@@ -170,6 +176,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
        VF610_ADC_CHAN(13, IIO_VOLTAGE),
        VF610_ADC_CHAN(14, IIO_VOLTAGE),
        VF610_ADC_CHAN(15, IIO_VOLTAGE),
+       VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
        /* sentinel */
 };
 
@@ -451,6 +458,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+       case IIO_CHAN_INFO_PROCESSED:
                mutex_lock(&indio_dev->mlock);
                reinit_completion(&info->completion);
 
@@ -468,7 +476,23 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
                        return ret;
                }
 
-               *val = info->value;
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       *val = info->value;
+                       break;
+               case IIO_TEMP:
+                       /*
+                       * Calculate in degree Celsius times 1000
+                       * Using sensor slope of 1.84 mV/°C and
+                       * V at 25°C of 696 mV
+                       */
+                       *val = 25000 - ((int)info->value - 864) * 1000000 / 1840;
+                       break;
+               default:
+                       mutex_unlock(&indio_dev->mlock);
+                       return -EINVAL;
+               }
+
                mutex_unlock(&indio_dev->mlock);
                return IIO_VAL_INT;
 
@@ -569,9 +593,9 @@ static int vf610_adc_probe(struct platform_device *pdev)
                return PTR_ERR(info->regs);
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
+       if (irq < 0) {
                dev_err(&pdev->dev, "no irq resource?\n");
-               return -EINVAL;
+               return irq;
        }
 
        ret = devm_request_irq(info->dev, irq,
@@ -586,8 +610,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
        if (IS_ERR(info->clk)) {
                dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
                                                PTR_ERR(info->clk));
-               ret = PTR_ERR(info->clk);
-               return ret;
+               return PTR_ERR(info->clk);
        }
 
        info->vref = devm_regulator_get(&pdev->dev, "vref");
@@ -681,17 +704,19 @@ static int vf610_adc_resume(struct device *dev)
 
        ret = clk_prepare_enable(info->clk);
        if (ret)
-               return ret;
+               goto disable_reg;
 
        vf610_adc_hw_init(info);
 
        return 0;
+
+disable_reg:
+       regulator_disable(info->vref);
+       return ret;
 }
 #endif
 
-static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops,
-                       vf610_adc_suspend,
-                       vf610_adc_resume);
+static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, vf610_adc_resume);
 
 static struct platform_driver vf610_adc_driver = {
        .probe          = vf610_adc_probe,
index 24cfe4e044f9b21ed5224f906602ea2c5898b54c..edd13d2b4121f7834c2e90eaca02e7a4f70c51b7 100644 (file)
@@ -44,18 +44,18 @@ st_sensors_write_data_with_mask_error:
        return err;
 }
 
-static int st_sensors_match_odr(struct st_sensors *sensor,
+static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
                        unsigned int odr, struct st_sensor_odr_avl *odr_out)
 {
        int i, ret = -EINVAL;
 
        for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
-               if (sensor->odr.odr_avl[i].hz == 0)
+               if (sensor_settings->odr.odr_avl[i].hz == 0)
                        goto st_sensors_match_odr_error;
 
-               if (sensor->odr.odr_avl[i].hz == odr) {
-                       odr_out->hz = sensor->odr.odr_avl[i].hz;
-                       odr_out->value = sensor->odr.odr_avl[i].value;
+               if (sensor_settings->odr.odr_avl[i].hz == odr) {
+                       odr_out->hz = sensor_settings->odr.odr_avl[i].hz;
+                       odr_out->value = sensor_settings->odr.odr_avl[i].value;
                        ret = 0;
                        break;
                }
@@ -71,23 +71,26 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
        struct st_sensor_odr_avl odr_out = {0, 0};
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
-       err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
+       err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
        if (err < 0)
                goto st_sensors_match_odr_error;
 
-       if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
-                       (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
+       if ((sdata->sensor_settings->odr.addr ==
+                                       sdata->sensor_settings->pw.addr) &&
+                               (sdata->sensor_settings->odr.mask ==
+                                       sdata->sensor_settings->pw.mask)) {
                if (sdata->enabled == true) {
                        err = st_sensors_write_data_with_mask(indio_dev,
-                               sdata->sensor->odr.addr,
-                               sdata->sensor->odr.mask,
+                               sdata->sensor_settings->odr.addr,
+                               sdata->sensor_settings->odr.mask,
                                odr_out.value);
                } else {
                        err = 0;
                }
        } else {
                err = st_sensors_write_data_with_mask(indio_dev,
-                       sdata->sensor->odr.addr, sdata->sensor->odr.mask,
+                       sdata->sensor_settings->odr.addr,
+                       sdata->sensor_settings->odr.mask,
                        odr_out.value);
        }
        if (err >= 0)
@@ -98,16 +101,16 @@ st_sensors_match_odr_error:
 }
 EXPORT_SYMBOL(st_sensors_set_odr);
 
-static int st_sensors_match_fs(struct st_sensors *sensor,
+static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
                                        unsigned int fs, int *index_fs_avl)
 {
        int i, ret = -EINVAL;
 
        for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
-               if (sensor->fs.fs_avl[i].num == 0)
+               if (sensor_settings->fs.fs_avl[i].num == 0)
                        goto st_sensors_match_odr_error;
 
-               if (sensor->fs.fs_avl[i].num == fs) {
+               if (sensor_settings->fs.fs_avl[i].num == fs) {
                        *index_fs_avl = i;
                        ret = 0;
                        break;
@@ -118,25 +121,24 @@ st_sensors_match_odr_error:
        return ret;
 }
 
-static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
-                                                               unsigned int fs)
+static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
 {
        int err, i = 0;
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
-       err = st_sensors_match_fs(sdata->sensor, fs, &i);
+       err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
        if (err < 0)
                goto st_accel_set_fullscale_error;
 
        err = st_sensors_write_data_with_mask(indio_dev,
-                               sdata->sensor->fs.addr,
-                               sdata->sensor->fs.mask,
-                               sdata->sensor->fs.fs_avl[i].value);
+                               sdata->sensor_settings->fs.addr,
+                               sdata->sensor_settings->fs.mask,
+                               sdata->sensor_settings->fs.fs_avl[i].value);
        if (err < 0)
                goto st_accel_set_fullscale_error;
 
        sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
-                                               &sdata->sensor->fs.fs_avl[i];
+                                       &sdata->sensor_settings->fs.fs_avl[i];
        return err;
 
 st_accel_set_fullscale_error:
@@ -153,10 +155,12 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
        if (enable) {
-               tmp_value = sdata->sensor->pw.value_on;
-               if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
-                       (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
-                       err = st_sensors_match_odr(sdata->sensor,
+               tmp_value = sdata->sensor_settings->pw.value_on;
+               if ((sdata->sensor_settings->odr.addr ==
+                                       sdata->sensor_settings->pw.addr) &&
+                               (sdata->sensor_settings->odr.mask ==
+                                       sdata->sensor_settings->pw.mask)) {
+                       err = st_sensors_match_odr(sdata->sensor_settings,
                                                        sdata->odr, &odr_out);
                        if (err < 0)
                                goto set_enable_error;
@@ -164,8 +168,8 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
                        found = true;
                }
                err = st_sensors_write_data_with_mask(indio_dev,
-                               sdata->sensor->pw.addr,
-                               sdata->sensor->pw.mask, tmp_value);
+                               sdata->sensor_settings->pw.addr,
+                               sdata->sensor_settings->pw.mask, tmp_value);
                if (err < 0)
                        goto set_enable_error;
 
@@ -175,9 +179,9 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
                        sdata->odr = odr_out.hz;
        } else {
                err = st_sensors_write_data_with_mask(indio_dev,
-                               sdata->sensor->pw.addr,
-                               sdata->sensor->pw.mask,
-                               sdata->sensor->pw.value_off);
+                               sdata->sensor_settings->pw.addr,
+                               sdata->sensor_settings->pw.mask,
+                               sdata->sensor_settings->pw.value_off);
                if (err < 0)
                        goto set_enable_error;
 
@@ -194,8 +198,9 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
        return st_sensors_write_data_with_mask(indio_dev,
-                               sdata->sensor->enable_axis.addr,
-                               sdata->sensor->enable_axis.mask, axis_enable);
+                               sdata->sensor_settings->enable_axis.addr,
+                               sdata->sensor_settings->enable_axis.mask,
+                               axis_enable);
 }
 EXPORT_SYMBOL(st_sensors_set_axis_enable);
 
@@ -236,13 +241,13 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
 EXPORT_SYMBOL(st_sensors_power_disable);
 
 static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
-                                      struct st_sensors_platform_data *pdata)
+                                       struct st_sensors_platform_data *pdata)
 {
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
        switch (pdata->drdy_int_pin) {
        case 1:
-               if (sdata->sensor->drdy_irq.mask_int1 == 0) {
+               if (sdata->sensor_settings->drdy_irq.mask_int1 == 0) {
                        dev_err(&indio_dev->dev,
                                        "DRDY on INT1 not available.\n");
                        return -EINVAL;
@@ -250,7 +255,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
                sdata->drdy_int_pin = 1;
                break;
        case 2:
-               if (sdata->sensor->drdy_irq.mask_int2 == 0) {
+               if (sdata->sensor_settings->drdy_irq.mask_int2 == 0) {
                        dev_err(&indio_dev->dev,
                                        "DRDY on INT2 not available.\n");
                        return -EINVAL;
@@ -318,7 +323,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 
        if (sdata->current_fullscale) {
                err = st_sensors_set_fullscale(indio_dev,
-                                              sdata->current_fullscale->num);
+                                               sdata->current_fullscale->num);
                if (err < 0)
                        return err;
        } else
@@ -330,7 +335,8 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 
        /* set BDU */
        err = st_sensors_write_data_with_mask(indio_dev,
-                       sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
+                                       sdata->sensor_settings->bdu.addr,
+                                       sdata->sensor_settings->bdu.mask, true);
        if (err < 0)
                return err;
 
@@ -346,26 +352,28 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
        u8 drdy_mask;
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
-       if (!sdata->sensor->drdy_irq.addr)
+       if (!sdata->sensor_settings->drdy_irq.addr)
                return 0;
 
        /* Enable/Disable the interrupt generator 1. */
-       if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
+       if (sdata->sensor_settings->drdy_irq.ig1.en_addr > 0) {
                err = st_sensors_write_data_with_mask(indio_dev,
-                       sdata->sensor->drdy_irq.ig1.en_addr,
-                       sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
+                               sdata->sensor_settings->drdy_irq.ig1.en_addr,
+                               sdata->sensor_settings->drdy_irq.ig1.en_mask,
+                               (int)enable);
                if (err < 0)
                        goto st_accel_set_dataready_irq_error;
        }
 
        if (sdata->drdy_int_pin == 1)
-               drdy_mask = sdata->sensor->drdy_irq.mask_int1;
+               drdy_mask = sdata->sensor_settings->drdy_irq.mask_int1;
        else
-               drdy_mask = sdata->sensor->drdy_irq.mask_int2;
+               drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
 
        /* Enable/Disable the interrupt generator for data ready. */
        err = st_sensors_write_data_with_mask(indio_dev,
-                       sdata->sensor->drdy_irq.addr, drdy_mask, (int)enable);
+                                       sdata->sensor_settings->drdy_irq.addr,
+                                       drdy_mask, (int)enable);
 
 st_accel_set_dataready_irq_error:
        return err;
@@ -378,8 +386,8 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
        for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
-               if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
-                               (sdata->sensor->fs.fs_avl[i].gain != 0)) {
+               if ((sdata->sensor_settings->fs.fs_avl[i].gain == scale) &&
+                               (sdata->sensor_settings->fs.fs_avl[i].gain != 0)) {
                        err = 0;
                        break;
                }
@@ -388,7 +396,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
                goto st_sensors_match_scale_error;
 
        err = st_sensors_set_fullscale(indio_dev,
-                                       sdata->sensor->fs.fs_avl[i].num);
+                               sdata->sensor_settings->fs.fs_avl[i].num);
 
 st_sensors_match_scale_error:
        return err;
@@ -439,7 +447,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
                if (err < 0)
                        goto out;
 
-               msleep((sdata->sensor->bootime * 1000) / sdata->odr);
+               msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
                err = st_sensors_read_axis_data(indio_dev, ch, val);
                if (err < 0)
                        goto out;
@@ -456,7 +464,8 @@ out:
 EXPORT_SYMBOL(st_sensors_read_info_raw);
 
 int st_sensors_check_device_support(struct iio_dev *indio_dev,
-                       int num_sensors_list, const struct st_sensors *sensors)
+                       int num_sensors_list,
+                       const struct st_sensor_settings *sensor_settings)
 {
        u8 wai;
        int i, n, err;
@@ -470,23 +479,24 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
        }
 
        for (i = 0; i < num_sensors_list; i++) {
-               if (sensors[i].wai == wai)
+               if (sensor_settings[i].wai == wai)
                        break;
        }
        if (i == num_sensors_list)
                goto device_not_supported;
 
-       for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
+       for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) {
                if (strcmp(indio_dev->name,
-                               &sensors[i].sensors_supported[n][0]) == 0)
+                               &sensor_settings[i].sensors_supported[n][0]) == 0)
                        break;
        }
-       if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
+       if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) {
                dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
                goto sensor_name_mismatch;
        }
 
-       sdata->sensor = (struct st_sensors *)&sensors[i];
+       sdata->sensor_settings =
+                       (struct st_sensor_settings *)&sensor_settings[i];
 
        return i;
 
@@ -508,11 +518,11 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
 
        mutex_lock(&indio_dev->mlock);
        for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
-               if (sdata->sensor->odr.odr_avl[i].hz == 0)
+               if (sdata->sensor_settings->odr.odr_avl[i].hz == 0)
                        break;
 
                len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
-                                       sdata->sensor->odr.odr_avl[i].hz);
+                               sdata->sensor_settings->odr.odr_avl[i].hz);
        }
        mutex_unlock(&indio_dev->mlock);
        buf[len - 1] = '\n';
@@ -530,11 +540,11 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
 
        mutex_lock(&indio_dev->mlock);
        for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
-               if (sdata->sensor->fs.fs_avl[i].num == 0)
+               if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
                        break;
 
                len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
-                                       sdata->sensor->fs.fs_avl[i].gain);
+                               sdata->sensor_settings->fs.fs_avl[i].gain);
        }
        mutex_unlock(&indio_dev->mlock);
        buf[len - 1] = '\n';
index bb6f3085f57bdd55314b7f469ab21ade801c6a4f..98cfee296d4622f92119b44af2fd3b1b0e59f8fc 100644 (file)
@@ -72,6 +72,7 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev,
        indio_dev->dev.parent = &client->dev;
        indio_dev->name = client->name;
 
+       sdata->dev = &client->dev;
        sdata->tf = &st_sensors_tf_i2c;
        sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
 }
index 251baf6abc2522138a838bc8c3ada1b1a2a8b607..78a6a1ab3ece00a51fa0f84ac0905762aede99d6 100644 (file)
@@ -111,6 +111,7 @@ void st_sensors_spi_configure(struct iio_dev *indio_dev,
        indio_dev->dev.parent = &spi->dev;
        indio_dev->name = spi->modalias;
 
+       sdata->dev = &spi->dev;
        sdata->tf = &st_sensors_tf_spi;
        sdata->get_irq_data_ready = st_sensors_spi_get_irq;
 }
index c197360c450bd8549a980a24941b322df4fca88f..5353d6328c544486db09b52cdcf2c25d5fa50598 100644 (file)
@@ -30,8 +30,7 @@ static const struct st_sensors_platform_data gyro_pdata = {
        .drdy_int_pin = 2,
 };
 
-int st_gyro_common_probe(struct iio_dev *indio_dev,
-                                       struct st_sensors_platform_data *pdata);
+int st_gyro_common_probe(struct iio_dev *indio_dev);
 void st_gyro_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
index f156fc6c5c6c11be88770b29cf11bfc78cd645e4..f07a2336f7dc705d4c328ac5d5caefe310516229 100644 (file)
@@ -103,7 +103,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(3)
 };
 
-static const struct st_sensors st_gyro_sensors[] = {
+static const struct st_sensor_settings st_gyro_sensors_settings[] = {
        {
                .wai = ST_GYRO_1_WAI_EXP,
                .sensors_supported = {
@@ -309,8 +309,7 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = {
 #define ST_GYRO_TRIGGER_OPS NULL
 #endif
 
-int st_gyro_common_probe(struct iio_dev *indio_dev,
-                                       struct st_sensors_platform_data *pdata)
+int st_gyro_common_probe(struct iio_dev *indio_dev)
 {
        struct st_sensor_data *gdata = iio_priv(indio_dev);
        int irq = gdata->get_irq_data_ready(indio_dev);
@@ -322,20 +321,22 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
        st_sensors_power_enable(indio_dev);
 
        err = st_sensors_check_device_support(indio_dev,
-                               ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors);
+                                       ARRAY_SIZE(st_gyro_sensors_settings),
+                                       st_gyro_sensors_settings);
        if (err < 0)
                return err;
 
        gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
-       gdata->multiread_bit = gdata->sensor->multi_read_bit;
-       indio_dev->channels = gdata->sensor->ch;
+       gdata->multiread_bit = gdata->sensor_settings->multi_read_bit;
+       indio_dev->channels = gdata->sensor_settings->ch;
        indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
 
        gdata->current_fullscale = (struct st_sensor_fullscale_avl *)
-                                               &gdata->sensor->fs.fs_avl[0];
-       gdata->odr = gdata->sensor->odr.odr_avl[0].hz;
+                                       &gdata->sensor_settings->fs.fs_avl[0];
+       gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz;
 
-       err = st_sensors_init_sensor(indio_dev, pdata);
+       err = st_sensors_init_sensor(indio_dev,
+                               (struct st_sensors_platform_data *)&gyro_pdata);
        if (err < 0)
                return err;
 
index 8fa0ad2ef4ef2cbe7d2daffcb9fd747ff5e40161..64480b16c6895373c626b47d250c17500cc03311 100644 (file)
@@ -67,13 +67,11 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        gdata = iio_priv(indio_dev);
-       gdata->dev = &client->dev;
        st_sensors_of_i2c_probe(client, st_gyro_of_match);
 
        st_sensors_i2c_configure(indio_dev, client, gdata);
 
-       err = st_gyro_common_probe(indio_dev,
-                               (struct st_sensors_platform_data *)&gyro_pdata);
+       err = st_gyro_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index b4ad3be2668768e7a4ef35979478ed033933007f..e59bead6bc3cb2fa8ba5a3cf2e34851cad20a33f 100644 (file)
@@ -29,12 +29,10 @@ static int st_gyro_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        gdata = iio_priv(indio_dev);
-       gdata->dev = &spi->dev;
 
        st_sensors_spi_configure(indio_dev, spi, gdata);
 
-       err = st_gyro_common_probe(indio_dev,
-                               (struct st_sensors_platform_data *)&gyro_pdata);
+       err = st_gyro_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index e116bd8dd0e42de168b9b084d03daaa6d8a4f521..4813b793b9f7f94439f06c59062e296f7d3b70d5 100644 (file)
@@ -22,4 +22,14 @@ config SI7005
          To compile this driver as a module, choose M here: the module
          will be called si7005.
 
+config SI7020
+       tristate "Si7013/20/21 Relative Humidity and Temperature Sensors"
+       depends on I2C
+       help
+         Say yes here to build support for the Silicon Labs Si7013/20/21
+         Relative Humidity and Temperature Sensors.
+
+         To compile this driver as a module, choose M here: the module
+         will be called si7020.
+
 endmenu
index e3f3d942e6460d16724d1fd24f6166c7e06e505b..86e2d26e9f4dd8edbfcaa3e4c3b24f5651dcfc91 100644 (file)
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_DHT11) += dht11.o
 obj-$(CONFIG_SI7005) += si7005.o
+obj-$(CONFIG_SI7020) += si7020.o
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
new file mode 100644 (file)
index 0000000..b541646
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
+ * Copyright (c) 2013,2014  Uplogix, Inc.
+ * David Barksdale <dbarksdale@uplogix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors
+ * are i2c devices which have an identical programming interface for
+ * measuring relative humidity and temperature. The Si7013 has an additional
+ * temperature input which this driver does not support.
+ *
+ * Data Sheets:
+ *   Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
+ *   Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
+ *   Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* Measure Relative Humidity, Hold Master Mode */
+#define SI7020CMD_RH_HOLD      0xE5
+/* Measure Temperature, Hold Master Mode */
+#define SI7020CMD_TEMP_HOLD    0xE3
+/* Software Reset */
+#define SI7020CMD_RESET                0xFE
+
+static int si7020_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan, int *val,
+                          int *val2, long mask)
+{
+       struct i2c_client *client = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = i2c_smbus_read_word_data(client,
+                                              chan->type == IIO_TEMP ?
+                                              SI7020CMD_TEMP_HOLD :
+                                              SI7020CMD_RH_HOLD);
+               if (ret < 0)
+                       return ret;
+               *val = ret >> 2;
+               if (chan->type == IIO_HUMIDITYRELATIVE)
+                       *val &= GENMASK(11, 0);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type == IIO_TEMP)
+                       *val = 175720; /* = 175.72 * 1000 */
+               else
+                       *val = 125 * 1000;
+               *val2 = 65536 >> 2;
+               return IIO_VAL_FRACTIONAL;
+       case IIO_CHAN_INFO_OFFSET:
+               /*
+                * Since iio_convert_raw_to_processed_unlocked assumes offset
+                * is an integer we have to round these values and lose
+                * accuracy.
+                * Relative humidity will be 0.0032959% too high and
+                * temperature will be 0.00277344 degrees too high.
+                * This is no big deal because it's within the accuracy of the
+                * sensor.
+                */
+               if (chan->type == IIO_TEMP)
+                       *val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */
+               else
+                       *val = -786; /* = -6 * (65536 >> 2) / 125 */
+               return IIO_VAL_INT;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_chan_spec si7020_channels[] = {
+       {
+               .type = IIO_HUMIDITYRELATIVE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+       },
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+       }
+};
+
+static const struct iio_info si7020_info = {
+       .read_raw = si7020_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static int si7020_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct iio_dev *indio_dev;
+       struct i2c_client **data;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WRITE_BYTE |
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -ENODEV;
+
+       /* Reset device, loads default settings. */
+       ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
+       if (ret < 0)
+               return ret;
+       /* Wait the maximum power-up time after software reset. */
+       msleep(15);
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       data = iio_priv(indio_dev);
+       *data = client;
+
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->name = dev_name(&client->dev);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &si7020_info;
+       indio_dev->channels = si7020_channels;
+       indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id si7020_id[] = {
+       { "si7020", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, si7020_id);
+
+static struct i2c_driver si7020_driver = {
+       .driver.name    = "si7020",
+       .probe          = si7020_probe,
+       .id_table       = si7020_id,
+};
+
+module_i2c_driver(si7020_driver);
+MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
+MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
+MODULE_LICENSE("GPL");
index f0846108d0067b4a979f3c3b86624b6e211cfa76..866fe904cba29e9f9f06d26fb0da16a9ce62b4d4 100644 (file)
@@ -100,6 +100,28 @@ static int iio_dev_node_match(struct device *dev, void *data)
        return dev->of_node == data && dev->type == &iio_device_type;
 }
 
+/**
+ * __of_iio_simple_xlate - translate iiospec to the IIO channel index
+ * @indio_dev: pointer to the iio_dev structure
+ * @iiospec:   IIO specifier as found in the device tree
+ *
+ * This is simple translation function, suitable for the most 1:1 mapped
+ * channels in IIO chips. This function performs only one sanity check:
+ * whether IIO index is less than num_channels (that is specified in the
+ * iio_dev).
+ */
+static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
+                               const struct of_phandle_args *iiospec)
+{
+       if (!iiospec->args_count)
+               return 0;
+
+       if (iiospec->args[0] >= indio_dev->num_channels)
+               return -EINVAL;
+
+       return iiospec->args[0];
+}
+
 static int __of_iio_channel_get(struct iio_channel *channel,
                                struct device_node *np, int index)
 {
@@ -122,18 +144,19 @@ static int __of_iio_channel_get(struct iio_channel *channel,
 
        indio_dev = dev_to_iio_dev(idev);
        channel->indio_dev = indio_dev;
-       index = iiospec.args_count ? iiospec.args[0] : 0;
-       if (index >= indio_dev->num_channels) {
-               err = -EINVAL;
+       if (indio_dev->info->of_xlate)
+               index = indio_dev->info->of_xlate(indio_dev, &iiospec);
+       else
+               index = __of_iio_simple_xlate(indio_dev, &iiospec);
+       if (index < 0)
                goto err_put;
-       }
        channel->channel = &indio_dev->channels[index];
 
        return 0;
 
 err_put:
        iio_device_put(indio_dev);
-       return err;
+       return index;
 }
 
 static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
index 694e33e0fb722f4d210904984c227a26dc4e4af1..7e81d00ef0c3d4129a4fe90fbffd9d50549ac7b5 100644 (file)
@@ -18,8 +18,7 @@
 #define LSM303DLM_MAGN_DEV_NAME                "lsm303dlm_magn"
 #define LIS3MDL_MAGN_DEV_NAME          "lis3mdl"
 
-int st_magn_common_probe(struct iio_dev *indio_dev,
-                                       struct st_sensors_platform_data *pdata);
+int st_magn_common_probe(struct iio_dev *indio_dev);
 void st_magn_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
index 68cae86dbd29e2ef7d93e111d05fa8178e451469..8ade473f99fee3ab35cb224eab0f69afebe2bf70 100644 (file)
@@ -149,7 +149,7 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(3)
 };
 
-static const struct st_sensors st_magn_sensors[] = {
+static const struct st_sensor_settings st_magn_sensors_settings[] = {
        {
                .wai = ST_MAGN_1_WAI_EXP,
                .sensors_supported = {
@@ -361,8 +361,7 @@ static const struct iio_info magn_info = {
        .write_raw = &st_magn_write_raw,
 };
 
-int st_magn_common_probe(struct iio_dev *indio_dev,
-                                       struct st_sensors_platform_data *pdata)
+int st_magn_common_probe(struct iio_dev *indio_dev)
 {
        struct st_sensor_data *mdata = iio_priv(indio_dev);
        int irq = mdata->get_irq_data_ready(indio_dev);
@@ -374,20 +373,21 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
        st_sensors_power_enable(indio_dev);
 
        err = st_sensors_check_device_support(indio_dev,
-                               ARRAY_SIZE(st_magn_sensors), st_magn_sensors);
+                                       ARRAY_SIZE(st_magn_sensors_settings),
+                                       st_magn_sensors_settings);
        if (err < 0)
                return err;
 
        mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS;
-       mdata->multiread_bit = mdata->sensor->multi_read_bit;
-       indio_dev->channels = mdata->sensor->ch;
+       mdata->multiread_bit = mdata->sensor_settings->multi_read_bit;
+       indio_dev->channels = mdata->sensor_settings->ch;
        indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
 
        mdata->current_fullscale = (struct st_sensor_fullscale_avl *)
-                                               &mdata->sensor->fs.fs_avl[0];
-       mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
+                                       &mdata->sensor_settings->fs.fs_avl[0];
+       mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz;
 
-       err = st_sensors_init_sensor(indio_dev, pdata);
+       err = st_sensors_init_sensor(indio_dev, NULL);
        if (err < 0)
                return err;
 
index 689250058442d09f2f858fdabf3172ad6069b73f..92e5c15452a3e4b0beb21d5a4f231ee8e3d79361 100644 (file)
@@ -51,12 +51,11 @@ static int st_magn_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        mdata = iio_priv(indio_dev);
-       mdata->dev = &client->dev;
        st_sensors_of_i2c_probe(client, st_magn_of_match);
 
        st_sensors_i2c_configure(indio_dev, client, mdata);
 
-       err = st_magn_common_probe(indio_dev, NULL);
+       err = st_magn_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index a6143ea51dfcb1d906e1a28bc85e7b40f92d8163..7adacf160146eba9af2e4f9034f064729a8e966d 100644 (file)
@@ -29,11 +29,10 @@ static int st_magn_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        mdata = iio_priv(indio_dev);
-       mdata->dev = &spi->dev;
 
        st_sensors_spi_configure(indio_dev, spi, mdata);
 
-       err = st_magn_common_probe(indio_dev, NULL);
+       err = st_magn_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index 15afbc9195211e2a5cc7cdd232574a999338a3b4..a3be53792072e454bcdcb38bee764c213d6d0ef6 100644 (file)
@@ -5,6 +5,17 @@
 
 menu "Pressure sensors"
 
+config BMP280
+       tristate "Bosch Sensortec BMP280 pressure sensor driver"
+       depends on I2C
+       select REGMAP_I2C
+       help
+        Say yes here to build support for Bosch Sensortec BMP280
+        pressure and temperature sensor.
+
+        To compile this driver as a module, choose M here: the module
+        will be called bmp280.
+
 config HID_SENSOR_PRESS
        depends on HID_SENSOR_HUB
        select IIO_BUFFER
index 90a37e85cf2159c3bd04b1a6b3386d05aac91d6f..88011f2ae00e4ca0f0955e97ea7f927ccc8eb4b1 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_BMP280) += bmp280.o
 obj-$(CONFIG_HID_SENSOR_PRESS)   += hid-sensor-press.o
 obj-$(CONFIG_MPL115) += mpl115.o
 obj-$(CONFIG_MPL3115) += mpl3115.o
diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c
new file mode 100644 (file)
index 0000000..75038da
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Driver for Bosch Sensortec BMP280 digital pressure sensor.
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "bmp280: " fmt
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define BMP280_REG_TEMP_XLSB           0xFC
+#define BMP280_REG_TEMP_LSB            0xFB
+#define BMP280_REG_TEMP_MSB            0xFA
+#define BMP280_REG_PRESS_XLSB          0xF9
+#define BMP280_REG_PRESS_LSB           0xF8
+#define BMP280_REG_PRESS_MSB           0xF7
+
+#define BMP280_REG_CONFIG              0xF5
+#define BMP280_REG_CTRL_MEAS           0xF4
+#define BMP280_REG_STATUS              0xF3
+#define BMP280_REG_RESET               0xE0
+#define BMP280_REG_ID                  0xD0
+
+#define BMP280_REG_COMP_TEMP_START     0x88
+#define BMP280_COMP_TEMP_REG_COUNT     6
+
+#define BMP280_REG_COMP_PRESS_START    0x8E
+#define BMP280_COMP_PRESS_REG_COUNT    18
+
+#define BMP280_FILTER_MASK             (BIT(4) | BIT(3) | BIT(2))
+#define BMP280_FILTER_OFF              0
+#define BMP280_FILTER_2X               BIT(2)
+#define BMP280_FILTER_4X               BIT(3)
+#define BMP280_FILTER_8X               (BIT(3) | BIT(2))
+#define BMP280_FILTER_16X              BIT(4)
+
+#define BMP280_OSRS_TEMP_MASK          (BIT(7) | BIT(6) | BIT(5))
+#define BMP280_OSRS_TEMP_SKIP          0
+#define BMP280_OSRS_TEMP_1X            BIT(5)
+#define BMP280_OSRS_TEMP_2X            BIT(6)
+#define BMP280_OSRS_TEMP_4X            (BIT(6) | BIT(5))
+#define BMP280_OSRS_TEMP_8X            BIT(7)
+#define BMP280_OSRS_TEMP_16X           (BIT(7) | BIT(5))
+
+#define BMP280_OSRS_PRESS_MASK         (BIT(4) | BIT(3) | BIT(2))
+#define BMP280_OSRS_PRESS_SKIP         0
+#define BMP280_OSRS_PRESS_1X           BIT(2)
+#define BMP280_OSRS_PRESS_2X           BIT(3)
+#define BMP280_OSRS_PRESS_4X           (BIT(3) | BIT(2))
+#define BMP280_OSRS_PRESS_8X           BIT(4)
+#define BMP280_OSRS_PRESS_16X          (BIT(4) | BIT(2))
+
+#define BMP280_MODE_MASK               (BIT(1) | BIT(0))
+#define BMP280_MODE_SLEEP              0
+#define BMP280_MODE_FORCED             BIT(0)
+#define BMP280_MODE_NORMAL             (BIT(1) | BIT(0))
+
+#define BMP280_CHIP_ID                 0x58
+#define BMP280_SOFT_RESET_VAL          0xB6
+
+struct bmp280_data {
+       struct i2c_client *client;
+       struct mutex lock;
+       struct regmap *regmap;
+
+       /*
+        * Carryover value from temperature conversion, used in pressure
+        * calculation.
+        */
+       s32 t_fine;
+};
+
+/* Compensation parameters. */
+struct bmp280_comp_temp {
+       u16 dig_t1;
+       s16 dig_t2, dig_t3;
+};
+
+struct bmp280_comp_press {
+       u16 dig_p1;
+       s16 dig_p2, dig_p3, dig_p4, dig_p5, dig_p6, dig_p7, dig_p8, dig_p9;
+};
+
+static const struct iio_chan_spec bmp280_channels[] = {
+       {
+               .type = IIO_PRESSURE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+       },
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+       },
+};
+
+static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case BMP280_REG_CONFIG:
+       case BMP280_REG_CTRL_MEAS:
+       case BMP280_REG_RESET:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case BMP280_REG_TEMP_XLSB:
+       case BMP280_REG_TEMP_LSB:
+       case BMP280_REG_TEMP_MSB:
+       case BMP280_REG_PRESS_XLSB:
+       case BMP280_REG_PRESS_LSB:
+       case BMP280_REG_PRESS_MSB:
+       case BMP280_REG_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config bmp280_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = BMP280_REG_TEMP_XLSB,
+       .cache_type = REGCACHE_RBTREE,
+
+       .writeable_reg = bmp280_is_writeable_reg,
+       .volatile_reg = bmp280_is_volatile_reg,
+};
+
+static int bmp280_read_compensation_temp(struct bmp280_data *data,
+                                        struct bmp280_comp_temp *comp)
+{
+       int ret;
+       __le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
+
+       ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
+                              buf, BMP280_COMP_TEMP_REG_COUNT);
+       if (ret < 0) {
+               dev_err(&data->client->dev,
+                       "failed to read temperature calibration parameters\n");
+               return ret;
+       }
+
+       comp->dig_t1 = (u16) le16_to_cpu(buf[0]);
+       comp->dig_t2 = (s16) le16_to_cpu(buf[1]);
+       comp->dig_t3 = (s16) le16_to_cpu(buf[2]);
+
+       return 0;
+}
+
+static int bmp280_read_compensation_press(struct bmp280_data *data,
+                                         struct bmp280_comp_press *comp)
+{
+       int ret;
+       __le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
+
+       ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
+                              buf, BMP280_COMP_PRESS_REG_COUNT);
+       if (ret < 0) {
+               dev_err(&data->client->dev,
+                       "failed to read pressure calibration parameters\n");
+               return ret;
+       }
+
+       comp->dig_p1 = (u16) le16_to_cpu(buf[0]);
+       comp->dig_p2 = (s16) le16_to_cpu(buf[1]);
+       comp->dig_p3 = (s16) le16_to_cpu(buf[2]);
+       comp->dig_p4 = (s16) le16_to_cpu(buf[3]);
+       comp->dig_p5 = (s16) le16_to_cpu(buf[4]);
+       comp->dig_p6 = (s16) le16_to_cpu(buf[5]);
+       comp->dig_p7 = (s16) le16_to_cpu(buf[6]);
+       comp->dig_p8 = (s16) le16_to_cpu(buf[7]);
+       comp->dig_p9 = (s16) le16_to_cpu(buf[8]);
+
+       return 0;
+}
+
+/*
+ * Returns temperature in DegC, resolution is 0.01 DegC.  Output value of
+ * "5123" equals 51.23 DegC.  t_fine carries fine temperature as global
+ * value.
+ *
+ * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ */
+static s32 bmp280_compensate_temp(struct bmp280_data *data,
+                                 struct bmp280_comp_temp *comp,
+                                 s32 adc_temp)
+{
+       s32 var1, var2, t;
+
+       var1 = (((adc_temp >> 3) - ((s32) comp->dig_t1 << 1)) *
+               ((s32) comp->dig_t2)) >> 11;
+       var2 = (((((adc_temp >> 4) - ((s32) comp->dig_t1)) *
+                 ((adc_temp >> 4) - ((s32) comp->dig_t1))) >> 12) *
+               ((s32) comp->dig_t3)) >> 14;
+
+       data->t_fine = var1 + var2;
+       t = (data->t_fine * 5 + 128) >> 8;
+
+       return t;
+}
+
+/*
+ * Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24
+ * integer bits and 8 fractional bits).  Output value of "24674867"
+ * represents 24674867/256 = 96386.2 Pa = 963.862 hPa
+ *
+ * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ */
+static u32 bmp280_compensate_press(struct bmp280_data *data,
+                                  struct bmp280_comp_press *comp,
+                                  s32 adc_press)
+{
+       s64 var1, var2, p;
+
+       var1 = ((s64) data->t_fine) - 128000;
+       var2 = var1 * var1 * (s64) comp->dig_p6;
+       var2 = var2 + ((var1 * (s64) comp->dig_p5) << 17);
+       var2 = var2 + (((s64) comp->dig_p4) << 35);
+       var1 = ((var1 * var1 * (s64) comp->dig_p3) >> 8) +
+               ((var1 * (s64) comp->dig_p2) << 12);
+       var1 = (((((s64) 1) << 47) + var1)) * ((s64) comp->dig_p1) >> 33;
+
+       if (var1 == 0)
+               return 0;
+
+       p = ((((s64) 1048576 - adc_press) << 31) - var2) * 3125;
+       p = div64_s64(p, var1);
+       var1 = (((s64) comp->dig_p9) * (p >> 13) * (p >> 13)) >> 25;
+       var2 = (((s64) comp->dig_p8) * p) >> 19;
+       p = ((p + var1 + var2) >> 8) + (((s64) comp->dig_p7) << 4);
+
+       return (u32) p;
+}
+
+static int bmp280_read_temp(struct bmp280_data *data,
+                           int *val)
+{
+       int ret;
+       __be32 tmp = 0;
+       s32 adc_temp, comp_temp;
+       struct bmp280_comp_temp comp;
+
+       ret = bmp280_read_compensation_temp(data, &comp);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
+                              (u8 *) &tmp, 3);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "failed to read temperature\n");
+               return ret;
+       }
+
+       adc_temp = be32_to_cpu(tmp) >> 12;
+       comp_temp = bmp280_compensate_temp(data, &comp, adc_temp);
+
+       /*
+        * val might be NULL if we're called by the read_press routine,
+        * who only cares about the carry over t_fine value.
+        */
+       if (val) {
+               *val = comp_temp * 10;
+               return IIO_VAL_INT;
+       }
+
+       return 0;
+}
+
+static int bmp280_read_press(struct bmp280_data *data,
+                            int *val, int *val2)
+{
+       int ret;
+       __be32 tmp = 0;
+       s32 adc_press;
+       u32 comp_press;
+       struct bmp280_comp_press comp;
+
+       ret = bmp280_read_compensation_press(data, &comp);
+       if (ret < 0)
+               return ret;
+
+       /* Read and compensate temperature so we get a reading of t_fine. */
+       ret = bmp280_read_temp(data, NULL);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
+                              (u8 *) &tmp, 3);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "failed to read pressure\n");
+               return ret;
+       }
+
+       adc_press = be32_to_cpu(tmp) >> 12;
+       comp_press = bmp280_compensate_press(data, &comp, adc_press);
+
+       *val = comp_press;
+       *val2 = 256000;
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int bmp280_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       int ret;
+       struct bmp280_data *data = iio_priv(indio_dev);
+
+       mutex_lock(&data->lock);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               switch (chan->type) {
+               case IIO_PRESSURE:
+                       ret = bmp280_read_press(data, val, val2);
+                       break;
+               case IIO_TEMP:
+                       ret = bmp280_read_temp(data, val);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       mutex_unlock(&data->lock);
+
+       return ret;
+}
+
+static const struct iio_info bmp280_info = {
+       .driver_module = THIS_MODULE,
+       .read_raw = &bmp280_read_raw,
+};
+
+static int bmp280_chip_init(struct bmp280_data *data)
+{
+       int ret;
+
+       ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_MEAS,
+                                BMP280_OSRS_TEMP_MASK |
+                                BMP280_OSRS_PRESS_MASK |
+                                BMP280_MODE_MASK,
+                                BMP280_OSRS_TEMP_2X |
+                                BMP280_OSRS_PRESS_16X |
+                                BMP280_MODE_NORMAL);
+       if (ret < 0) {
+               dev_err(&data->client->dev,
+                       "failed to write config register\n");
+               return ret;
+       }
+
+       ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
+                                BMP280_FILTER_MASK,
+                                BMP280_FILTER_4X);
+       if (ret < 0) {
+               dev_err(&data->client->dev,
+                       "failed to write config register\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int bmp280_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int ret;
+       struct iio_dev *indio_dev;
+       struct bmp280_data *data;
+       unsigned int chip_id;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, indio_dev);
+       data = iio_priv(indio_dev);
+       mutex_init(&data->lock);
+       data->client = client;
+
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->name = id->name;
+       indio_dev->channels = bmp280_channels;
+       indio_dev->num_channels = ARRAY_SIZE(bmp280_channels);
+       indio_dev->info = &bmp280_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       data->regmap = devm_regmap_init_i2c(client, &bmp280_regmap_config);
+       if (IS_ERR(data->regmap)) {
+               dev_err(&client->dev, "failed to allocate register map\n");
+               return PTR_ERR(data->regmap);
+       }
+
+       ret = regmap_read(data->regmap, BMP280_REG_ID, &chip_id);
+       if (ret < 0)
+               return ret;
+       if (chip_id != BMP280_CHIP_ID) {
+               dev_err(&client->dev, "bad chip id.  expected %x got %x\n",
+                       BMP280_CHIP_ID, chip_id);
+               return -EINVAL;
+       }
+
+       ret = bmp280_chip_init(data);
+       if (ret < 0)
+               return ret;
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct acpi_device_id bmp280_acpi_match[] = {
+       {"BMP0280", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match);
+
+static const struct i2c_device_id bmp280_id[] = {
+       {"bmp280", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, bmp280_id);
+
+static struct i2c_driver bmp280_driver = {
+       .driver = {
+               .name   = "bmp280",
+               .acpi_match_table = ACPI_PTR(bmp280_acpi_match),
+       },
+       .probe          = bmp280_probe,
+       .id_table       = bmp280_id,
+};
+module_i2c_driver(bmp280_driver);
+
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP280 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
index 242943c0c4e496c4b054bb5426cc06c5380accdb..f5f41490060b95be8e38ce5fb79bcee15e0dffc1 100644 (file)
@@ -26,8 +26,7 @@ static const struct st_sensors_platform_data default_press_pdata = {
        .drdy_int_pin = 1,
 };
 
-int st_press_common_probe(struct iio_dev *indio_dev,
-                                       struct st_sensors_platform_data *pdata);
+int st_press_common_probe(struct iio_dev *indio_dev);
 void st_press_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
index b37b1c9ac93210dc755ac95830fc956e428333ce..2ff53f222352ca66d4057ff054732e6a0a581db6 100644 (file)
@@ -38,10 +38,10 @@ static int st_press_buffer_preenable(struct iio_dev *indio_dev)
 static int st_press_buffer_postenable(struct iio_dev *indio_dev)
 {
        int err;
-       struct st_sensor_data *pdata = iio_priv(indio_dev);
+       struct st_sensor_data *press_data = iio_priv(indio_dev);
 
-       pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
-       if (pdata->buffer_data == NULL) {
+       press_data->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+       if (press_data->buffer_data == NULL) {
                err = -ENOMEM;
                goto allocate_memory_error;
        }
@@ -53,7 +53,7 @@ static int st_press_buffer_postenable(struct iio_dev *indio_dev)
        return err;
 
 st_press_buffer_postenable_error:
-       kfree(pdata->buffer_data);
+       kfree(press_data->buffer_data);
 allocate_memory_error:
        return err;
 }
@@ -61,7 +61,7 @@ allocate_memory_error:
 static int st_press_buffer_predisable(struct iio_dev *indio_dev)
 {
        int err;
-       struct st_sensor_data *pdata = iio_priv(indio_dev);
+       struct st_sensor_data *press_data = iio_priv(indio_dev);
 
        err = iio_triggered_buffer_predisable(indio_dev);
        if (err < 0)
@@ -70,7 +70,7 @@ static int st_press_buffer_predisable(struct iio_dev *indio_dev)
        err = st_sensors_set_enable(indio_dev, false);
 
 st_press_buffer_predisable_error:
-       kfree(pdata->buffer_data);
+       kfree(press_data->buffer_data);
        return err;
 }
 
index 473d914ef470482dda3d3d95bbb1f8e0e4a0c738..97baf40d424bd599687b124062081364f94b487e 100644 (file)
@@ -175,7 +175,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(1)
 };
 
-static const struct st_sensors st_press_sensors[] = {
+static const struct st_sensor_settings st_press_sensors_settings[] = {
        {
                .wai = ST_PRESS_LPS331AP_WAI_EXP,
                .sensors_supported = {
@@ -333,7 +333,7 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
                                                        int *val2, long mask)
 {
        int err;
-       struct st_sensor_data *pdata = iio_priv(indio_dev);
+       struct st_sensor_data *press_data = iio_priv(indio_dev);
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
@@ -347,10 +347,10 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
 
                switch (ch->type) {
                case IIO_PRESSURE:
-                       *val2 = pdata->current_fullscale->gain;
+                       *val2 = press_data->current_fullscale->gain;
                        break;
                case IIO_TEMP:
-                       *val2 = pdata->current_fullscale->gain2;
+                       *val2 = press_data->current_fullscale->gain2;
                        break;
                default:
                        err = -EINVAL;
@@ -371,7 +371,7 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
 
                return IIO_VAL_FRACTIONAL;
        case IIO_CHAN_INFO_SAMP_FREQ:
-               *val = pdata->odr;
+               *val = press_data->odr;
                return IIO_VAL_INT;
        default:
                return -EINVAL;
@@ -409,11 +409,10 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
 #define ST_PRESS_TRIGGER_OPS NULL
 #endif
 
-int st_press_common_probe(struct iio_dev *indio_dev,
-                               struct st_sensors_platform_data *plat_data)
+int st_press_common_probe(struct iio_dev *indio_dev)
 {
-       struct st_sensor_data *pdata = iio_priv(indio_dev);
-       int irq = pdata->get_irq_data_ready(indio_dev);
+       struct st_sensor_data *press_data = iio_priv(indio_dev);
+       int irq = press_data->get_irq_data_ready(indio_dev);
        int err;
 
        indio_dev->modes = INDIO_DIRECT_MODE;
@@ -422,28 +421,30 @@ int st_press_common_probe(struct iio_dev *indio_dev,
        st_sensors_power_enable(indio_dev);
 
        err = st_sensors_check_device_support(indio_dev,
-                                             ARRAY_SIZE(st_press_sensors),
-                                             st_press_sensors);
+                                       ARRAY_SIZE(st_press_sensors_settings),
+                                       st_press_sensors_settings);
        if (err < 0)
                return err;
 
-       pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
-       pdata->multiread_bit     = pdata->sensor->multi_read_bit;
-       indio_dev->channels      = pdata->sensor->ch;
-       indio_dev->num_channels  = pdata->sensor->num_ch;
+       press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
+       press_data->multiread_bit = press_data->sensor_settings->multi_read_bit;
+       indio_dev->channels = press_data->sensor_settings->ch;
+       indio_dev->num_channels = press_data->sensor_settings->num_ch;
 
-       if (pdata->sensor->fs.addr != 0)
-               pdata->current_fullscale = (struct st_sensor_fullscale_avl *)
-                       &pdata->sensor->fs.fs_avl[0];
+       if (press_data->sensor_settings->fs.addr != 0)
+               press_data->current_fullscale =
+                       (struct st_sensor_fullscale_avl *)
+                               &press_data->sensor_settings->fs.fs_avl[0];
 
-       pdata->odr = pdata->sensor->odr.odr_avl[0].hz;
+       press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
 
        /* Some devices don't support a data ready pin. */
-       if (!plat_data && pdata->sensor->drdy_irq.addr)
-               plat_data =
+       if (!press_data->dev->platform_data &&
+                               press_data->sensor_settings->drdy_irq.addr)
+               press_data->dev->platform_data =
                        (struct st_sensors_platform_data *)&default_press_pdata;
 
-       err = st_sensors_init_sensor(indio_dev, plat_data);
+       err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
        if (err < 0)
                return err;
 
@@ -479,12 +480,12 @@ EXPORT_SYMBOL(st_press_common_probe);
 
 void st_press_common_remove(struct iio_dev *indio_dev)
 {
-       struct st_sensor_data *pdata = iio_priv(indio_dev);
+       struct st_sensor_data *press_data = iio_priv(indio_dev);
 
        st_sensors_power_disable(indio_dev);
 
        iio_device_unregister(indio_dev);
-       if (pdata->get_irq_data_ready(indio_dev) > 0)
+       if (press_data->get_irq_data_ready(indio_dev) > 0)
                st_sensors_deallocate_trigger(indio_dev);
 
        st_press_deallocate_ring(indio_dev);
index acaf165260bba1d98e71f132fb7259c9f1a179d6..137788bba4a322a772f517a2348f165be24a8400 100644 (file)
@@ -43,20 +43,19 @@ static int st_press_i2c_probe(struct i2c_client *client,
                                                const struct i2c_device_id *id)
 {
        struct iio_dev *indio_dev;
-       struct st_sensor_data *pdata;
+       struct st_sensor_data *press_data;
        int err;
 
-       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*pdata));
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data));
        if (!indio_dev)
                return -ENOMEM;
 
-       pdata = iio_priv(indio_dev);
-       pdata->dev = &client->dev;
+       press_data = iio_priv(indio_dev);
        st_sensors_of_i2c_probe(client, st_press_of_match);
 
-       st_sensors_i2c_configure(indio_dev, client, pdata);
+       st_sensors_i2c_configure(indio_dev, client, press_data);
 
-       err = st_press_common_probe(indio_dev, client->dev.platform_data);
+       err = st_press_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index f45d430ec52968bf42cb7b634263709fb5db69f4..1ffa6d4d349c1462f4326a6af3738b1fc3e9828a 100644 (file)
 static int st_press_spi_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
-       struct st_sensor_data *pdata;
+       struct st_sensor_data *press_data;
        int err;
 
-       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*pdata));
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*press_data));
        if (indio_dev == NULL)
                return -ENOMEM;
 
-       pdata = iio_priv(indio_dev);
-       pdata->dev = &spi->dev;
+       press_data = iio_priv(indio_dev);
 
-       st_sensors_spi_configure(indio_dev, spi, pdata);
+       st_sensors_spi_configure(indio_dev, spi, press_data);
 
-       err = st_press_common_probe(indio_dev, spi->dev.platform_data);
+       err = st_press_common_probe(indio_dev);
        if (err < 0)
                return err;
 
index 5e780ef206f3c48774cb3f2d3a587ba0c6be1571..78244e6343f60008a7f2368fe67afd1b73a8cbe7 100644 (file)
@@ -95,7 +95,7 @@ static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)
        *val = ret;
 
        return 0;
-};
+}
 
 static int as3935_write(struct as3935_state *st,
                                unsigned int reg,
@@ -107,7 +107,7 @@ static int as3935_write(struct as3935_state *st,
        buf[1] = val;
 
        return spi_write(st->spi, buf, 2);
-};
+}
 
 static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
                                        struct device_attribute *attr,
@@ -122,7 +122,7 @@ static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
        val = (val & AS3935_AFE_MASK) >> 1;
 
        return sprintf(buf, "%d\n", val);
-};
+}
 
 static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
                                        struct device_attribute *attr,
@@ -142,7 +142,7 @@ static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
        as3935_write(st, AS3935_AFE_GAIN, val << 1);
 
        return len;
-};
+}
 
 static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
        as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);
@@ -214,7 +214,7 @@ err_read:
        iio_trigger_notify_done(indio_dev->trig);
 
        return IRQ_HANDLED;
-};
+}
 
 static const struct iio_trigger_ops iio_interrupt_trigger_ops = {
        .owner = THIS_MODULE,
@@ -238,7 +238,7 @@ static void as3935_event_work(struct work_struct *work)
                dev_warn(&st->spi->dev, "noise level is too high");
                break;
        }
-};
+}
 
 static irqreturn_t as3935_interrupt_handler(int irq, void *private)
 {
@@ -417,7 +417,7 @@ unregister_trigger:
        iio_trigger_unregister(st->trig);
 
        return ret;
-};
+}
 
 static int as3935_remove(struct spi_device *spi)
 {
@@ -429,7 +429,7 @@ static int as3935_remove(struct spi_device *spi)
        iio_trigger_unregister(st->trig);
 
        return 0;
-};
+}
 
 static const struct spi_device_id as3935_id[] = {
        {"as3935", 0},
index 31dfb21587ff3a94db378e5a19b36edd8a6c8c56..de4647e2495e9a645da8c96fb34718926422e803 100644 (file)
@@ -162,11 +162,12 @@ int main(int argc, char **argv)
        char *buffer_access;
        int scan_size;
        int noevents = 0;
+       int notrigger = 0;
        char *dummy;
 
        struct iio_channel_info *channels;
 
-       while ((c = getopt(argc, argv, "l:w:c:et:n:")) != -1) {
+       while ((c = getopt(argc, argv, "l:w:c:et:n:g")) != -1) {
                switch (c) {
                case 'n':
                        device_name = optarg;
@@ -187,6 +188,9 @@ int main(int argc, char **argv)
                case 'l':
                        buf_len = strtoul(optarg, &dummy, 10);
                        break;
+               case 'g':
+                       notrigger = 1;
+                       break;
                case '?':
                        return -1;
                }
@@ -205,28 +209,32 @@ int main(int argc, char **argv)
        printf("iio device number being used is %d\n", dev_num);
 
        asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
-       if (trigger_name == NULL) {
-               /*
-                * Build the trigger name. If it is device associated its
-                * name is <device_name>_dev[n] where n matches the device
-                * number found above
-                */
-               ret = asprintf(&trigger_name,
-                              "%s-dev%d", device_name, dev_num);
-               if (ret < 0) {
-                       ret = -ENOMEM;
-                       goto error_ret;
+
+       if (!notrigger) {
+               if (trigger_name == NULL) {
+                       /*
+                        * Build the trigger name. If it is device associated
+                        * its name is <device_name>_dev[n] where n matches
+                        * the device number found above.
+                        */
+                       ret = asprintf(&trigger_name,
+                                      "%s-dev%d", device_name, dev_num);
+                       if (ret < 0) {
+                               ret = -ENOMEM;
+                               goto error_ret;
+                       }
                }
-       }
 
-       /* Verify the trigger exists */
-       trig_num = find_type_by_name(trigger_name, "trigger");
-       if (trig_num < 0) {
-               printf("Failed to find the trigger %s\n", trigger_name);
-               ret = -ENODEV;
-               goto error_free_triggername;
-       }
-       printf("iio trigger number being used is %d\n", trig_num);
+               /* Verify the trigger exists */
+               trig_num = find_type_by_name(trigger_name, "trigger");
+               if (trig_num < 0) {
+                       printf("Failed to find the trigger %s\n", trigger_name);
+                       ret = -ENODEV;
+                       goto error_free_triggername;
+               }
+               printf("iio trigger number being used is %d\n", trig_num);
+       } else
+               printf("trigger-less mode selected\n");
 
        /*
         * Parse the files in scan_elements to identify what channels are
@@ -250,14 +258,18 @@ int main(int argc, char **argv)
                ret = -ENOMEM;
                goto error_free_triggername;
        }
-       printf("%s %s\n", dev_dir_name, trigger_name);
-       /* Set the device trigger to be the data ready trigger found above */
-       ret = write_sysfs_string_and_verify("trigger/current_trigger",
-                                       dev_dir_name,
-                                       trigger_name);
-       if (ret < 0) {
-               printf("Failed to write current_trigger file\n");
-               goto error_free_buf_dir_name;
+
+       if (!notrigger) {
+               printf("%s %s\n", dev_dir_name, trigger_name);
+               /* Set the device trigger to be the data ready trigger found
+                * above */
+               ret = write_sysfs_string_and_verify("trigger/current_trigger",
+                                                   dev_dir_name,
+                                                   trigger_name);
+               if (ret < 0) {
+                       printf("Failed to write current_trigger file\n");
+                       goto error_free_buf_dir_name;
+               }
        }
 
        /* Setup ring buffer parameters */
@@ -327,9 +339,10 @@ int main(int argc, char **argv)
        if (ret < 0)
                goto error_close_buffer_access;
 
-       /* Disconnect the trigger - just write a dummy name. */
-       write_sysfs_string("trigger/current_trigger",
-                       dev_dir_name, "NULL");
+       if (!notrigger)
+               /* Disconnect the trigger - just write a dummy name. */
+               write_sysfs_string("trigger/current_trigger",
+                                  dev_dir_name, "NULL");
 
 error_close_buffer_access:
        close(fp);
index 61f94221b8b733ae46542fc24913cc5fb6cddead..9efc77b0ebdd4d8411f055e177b0f74433d5cefe 100644 (file)
@@ -35,6 +35,7 @@ irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private)
                iio_trigger_poll(st->trig);
                return IRQ_HANDLED;
        }
+
        return IRQ_WAKE_THREAD;
 }
 
index d8257ab60bacdc932b05dd1333a2218b00e257d4..2c476acb87d92784529690c6dd1b5d299a9aa2fe 100644 (file)
@@ -164,7 +164,7 @@ struct st_sensor_transfer_function {
 };
 
 /**
- * struct st_sensors - ST sensors list
+ * struct st_sensor_settings - ST specific sensor settings
  * @wai: Contents of WhoAmI register.
  * @sensors_supported: List of supported sensors by struct itself.
  * @ch: IIO channels for the sensor.
@@ -177,7 +177,7 @@ struct st_sensor_transfer_function {
  * @multi_read_bit: Use or not particular bit for [I2C/SPI] multi-read.
  * @bootime: samples to discard when sensor passing from power-down to power-up.
  */
-struct st_sensors {
+struct st_sensor_settings {
        u8 wai;
        char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME];
        struct iio_chan_spec *ch;
@@ -196,7 +196,7 @@ struct st_sensors {
  * struct st_sensor_data - ST sensor device status
  * @dev: Pointer to instance of struct device (I2C or SPI).
  * @trig: The trigger in use by the core driver.
- * @sensor: Pointer to the current sensor struct in use.
+ * @sensor_settings: Pointer to the specific sensor settings in use.
  * @current_fullscale: Maximum range of measure by the sensor.
  * @vdd: Pointer to sensor's Vdd power supply
  * @vdd_io: Pointer to sensor's Vdd-IO power supply
@@ -213,7 +213,7 @@ struct st_sensors {
 struct st_sensor_data {
        struct device *dev;
        struct iio_trigger *trig;
-       struct st_sensors *sensor;
+       struct st_sensor_settings *sensor_settings;
        struct st_sensor_fullscale_avl *current_fullscale;
        struct regulator *vdd;
        struct regulator *vdd_io;
@@ -279,7 +279,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
                                struct iio_chan_spec const *ch, int *val);
 
 int st_sensors_check_device_support(struct iio_dev *indio_dev,
-                       int num_sensors_list, const struct st_sensors *sensors);
+       int num_sensors_list, const struct st_sensor_settings *sensor_settings);
 
 ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
                                struct device_attribute *attr, char *buf);
index 15dc6bc2bdd2e0da285ea333ef014ba576b4bbff..3642ce7ef512cba9ec681da16f4727f08e58b674 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/cdev.h>
 #include <linux/iio/types.h>
+#include <linux/of.h>
 /* IIO TODO LIST */
 /*
  * Provide means of adjusting timer accuracy.
@@ -326,6 +327,11 @@ struct iio_dev;
  * @update_scan_mode:  function to configure device and scan buffer when
  *                     channels have changed
  * @debugfs_reg_access:        function to read or write register value of device
+ * @of_xlate:          function pointer to obtain channel specifier index.
+ *                     When #iio-cells is greater than '0', the driver could
+ *                     provide a custom of_xlate function that reads the
+ *                     *args* and returns the appropriate index in registered
+ *                     IIO channels array.
  **/
 struct iio_info {
        struct module                   *driver_module;
@@ -385,6 +391,8 @@ struct iio_info {
        int (*debugfs_reg_access)(struct iio_dev *indio_dev,
                                  unsigned reg, unsigned writeval,
                                  unsigned *readval);
+       int (*of_xlate)(struct iio_dev *indio_dev,
+                       const struct of_phandle_args *iiospec);
 };
 
 /**