diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-28 08:26:16 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-28 08:26:16 +0100 |
commit | 2d2139c5c746ec61024fdfa9c36e4e034bb18e59 (patch) | |
tree | b3f4a9b0dd5eae44dfe58d260b78e06c2fb41361 /drivers | |
parent | 469554a148e86aa761fbbfcbca496be64f38568a (diff) | |
parent | 6f771d0b338d59c492699814b0fe554f9d1ee27c (diff) | |
download | linux-2d2139c5c746ec61024fdfa9c36e4e034bb18e59.tar.bz2 |
Merge tag 'iio-for-4.10d' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Fourth set of IIO new device support, features and cleaups for the 4.10 cycle.
Probably the final set before the merge window unless things get significantly
delayed.
New device support
* STM32 ADC core
- new driver. Interesting device with up to 3 ADCs with complex triggering
options that will follow later. Note split into an 'mfd like' core that
handles the interrupt sharing etc between the various instances present and
a per ADC section that is instantiated as many times as needed.
- device tree bindings.
Cleanups and minor fixes
* st_accel
- inline per sensor data as the defines don't add any meaning and make it
much harder to check if a given sensor has the right values.
* hid-magnetometer
- sort out the associations of the associated attributes with the two types.
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/iio/accel/st_accel_core.c | 602 | ||||
-rw-r--r-- | drivers/iio/adc/Kconfig | 22 | ||||
-rw-r--r-- | drivers/iio/adc/Makefile | 2 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc-core.c | 303 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc-core.h | 52 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc.c | 518 | ||||
-rw-r--r-- | drivers/iio/light/tsl2583.c | 2 | ||||
-rw-r--r-- | drivers/iio/magnetometer/hid-sensor-magn-3d.c | 147 |
8 files changed, 1216 insertions, 432 deletions
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index bdb619a28a4e..f6b6d42385e1 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -43,200 +43,6 @@ #define ST_ACCEL_FS_AVL_200G 200 #define ST_ACCEL_FS_AVL_400G 400 -/* CUSTOM VALUES FOR SENSOR 1 */ -#define ST_ACCEL_1_WAI_EXP 0x33 -#define ST_ACCEL_1_ODR_ADDR 0x20 -#define ST_ACCEL_1_ODR_MASK 0xf0 -#define ST_ACCEL_1_ODR_AVL_1HZ_VAL 0x01 -#define ST_ACCEL_1_ODR_AVL_10HZ_VAL 0x02 -#define ST_ACCEL_1_ODR_AVL_25HZ_VAL 0x03 -#define ST_ACCEL_1_ODR_AVL_50HZ_VAL 0x04 -#define ST_ACCEL_1_ODR_AVL_100HZ_VAL 0x05 -#define ST_ACCEL_1_ODR_AVL_200HZ_VAL 0x06 -#define ST_ACCEL_1_ODR_AVL_400HZ_VAL 0x07 -#define ST_ACCEL_1_ODR_AVL_1600HZ_VAL 0x08 -#define ST_ACCEL_1_FS_ADDR 0x23 -#define ST_ACCEL_1_FS_MASK 0x30 -#define ST_ACCEL_1_FS_AVL_2_VAL 0x00 -#define ST_ACCEL_1_FS_AVL_4_VAL 0x01 -#define ST_ACCEL_1_FS_AVL_8_VAL 0x02 -#define ST_ACCEL_1_FS_AVL_16_VAL 0x03 -#define ST_ACCEL_1_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000) -#define ST_ACCEL_1_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000) -#define ST_ACCEL_1_FS_AVL_8_GAIN IIO_G_TO_M_S_2(4000) -#define ST_ACCEL_1_FS_AVL_16_GAIN IIO_G_TO_M_S_2(12000) -#define ST_ACCEL_1_BDU_ADDR 0x23 -#define ST_ACCEL_1_BDU_MASK 0x80 -#define ST_ACCEL_1_DRDY_IRQ_ADDR 0x22 -#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK 0x10 -#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK 0x08 -#define ST_ACCEL_1_IHL_IRQ_ADDR 0x25 -#define ST_ACCEL_1_IHL_IRQ_MASK 0x02 -#define ST_ACCEL_1_MULTIREAD_BIT true - -/* CUSTOM VALUES FOR SENSOR 2 */ -#define ST_ACCEL_2_WAI_EXP 0x32 -#define ST_ACCEL_2_ODR_ADDR 0x20 -#define ST_ACCEL_2_ODR_MASK 0x18 -#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00 -#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01 -#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02 -#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03 -#define ST_ACCEL_2_PW_ADDR 0x20 -#define ST_ACCEL_2_PW_MASK 0xe0 -#define ST_ACCEL_2_FS_ADDR 0x23 -#define ST_ACCEL_2_FS_MASK 0x30 -#define ST_ACCEL_2_FS_AVL_2_VAL 0X00 -#define ST_ACCEL_2_FS_AVL_4_VAL 0X01 -#define ST_ACCEL_2_FS_AVL_8_VAL 0x03 -#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000) -#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000) -#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900) -#define ST_ACCEL_2_BDU_ADDR 0x23 -#define ST_ACCEL_2_BDU_MASK 0x80 -#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22 -#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK 0x02 -#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK 0x10 -#define ST_ACCEL_2_IHL_IRQ_ADDR 0x22 -#define ST_ACCEL_2_IHL_IRQ_MASK 0x80 -#define ST_ACCEL_2_OD_IRQ_ADDR 0x22 -#define ST_ACCEL_2_OD_IRQ_MASK 0x40 -#define ST_ACCEL_2_MULTIREAD_BIT true - -/* CUSTOM VALUES FOR SENSOR 3 */ -#define ST_ACCEL_3_WAI_EXP 0x40 -#define ST_ACCEL_3_ODR_ADDR 0x20 -#define ST_ACCEL_3_ODR_MASK 0xf0 -#define ST_ACCEL_3_ODR_AVL_3HZ_VAL 0x01 -#define ST_ACCEL_3_ODR_AVL_6HZ_VAL 0x02 -#define ST_ACCEL_3_ODR_AVL_12HZ_VAL 0x03 -#define ST_ACCEL_3_ODR_AVL_25HZ_VAL 0x04 -#define ST_ACCEL_3_ODR_AVL_50HZ_VAL 0x05 -#define ST_ACCEL_3_ODR_AVL_100HZ_VAL 0x06 -#define ST_ACCEL_3_ODR_AVL_200HZ_VAL 0x07 -#define ST_ACCEL_3_ODR_AVL_400HZ_VAL 0x08 -#define ST_ACCEL_3_ODR_AVL_800HZ_VAL 0x09 -#define ST_ACCEL_3_ODR_AVL_1600HZ_VAL 0x0a -#define ST_ACCEL_3_FS_ADDR 0x24 -#define ST_ACCEL_3_FS_MASK 0x38 -#define ST_ACCEL_3_FS_AVL_2_VAL 0X00 -#define ST_ACCEL_3_FS_AVL_4_VAL 0X01 -#define ST_ACCEL_3_FS_AVL_6_VAL 0x02 -#define ST_ACCEL_3_FS_AVL_8_VAL 0x03 -#define ST_ACCEL_3_FS_AVL_16_VAL 0x04 -#define ST_ACCEL_3_FS_AVL_2_GAIN IIO_G_TO_M_S_2(61) -#define ST_ACCEL_3_FS_AVL_4_GAIN IIO_G_TO_M_S_2(122) -#define ST_ACCEL_3_FS_AVL_6_GAIN IIO_G_TO_M_S_2(183) -#define ST_ACCEL_3_FS_AVL_8_GAIN IIO_G_TO_M_S_2(244) -#define ST_ACCEL_3_FS_AVL_16_GAIN IIO_G_TO_M_S_2(732) -#define ST_ACCEL_3_BDU_ADDR 0x20 -#define ST_ACCEL_3_BDU_MASK 0x08 -#define ST_ACCEL_3_DRDY_IRQ_ADDR 0x23 -#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK 0x80 -#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK 0x00 -#define ST_ACCEL_3_IHL_IRQ_ADDR 0x23 -#define ST_ACCEL_3_IHL_IRQ_MASK 0x40 -#define ST_ACCEL_3_IG1_EN_ADDR 0x23 -#define ST_ACCEL_3_IG1_EN_MASK 0x08 -#define ST_ACCEL_3_MULTIREAD_BIT false - -/* CUSTOM VALUES FOR SENSOR 4 */ -#define ST_ACCEL_4_WAI_EXP 0x3a -#define ST_ACCEL_4_ODR_ADDR 0x20 -#define ST_ACCEL_4_ODR_MASK 0x30 /* DF1 and DF0 */ -#define ST_ACCEL_4_ODR_AVL_40HZ_VAL 0x00 -#define ST_ACCEL_4_ODR_AVL_160HZ_VAL 0x01 -#define ST_ACCEL_4_ODR_AVL_640HZ_VAL 0x02 -#define ST_ACCEL_4_ODR_AVL_2560HZ_VAL 0x03 -#define ST_ACCEL_4_PW_ADDR 0x20 -#define ST_ACCEL_4_PW_MASK 0xc0 -#define ST_ACCEL_4_FS_ADDR 0x21 -#define ST_ACCEL_4_FS_MASK 0x80 -#define ST_ACCEL_4_FS_AVL_2_VAL 0X00 -#define ST_ACCEL_4_FS_AVL_6_VAL 0X01 -#define ST_ACCEL_4_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1024) -#define ST_ACCEL_4_FS_AVL_6_GAIN IIO_G_TO_M_S_2(340) -#define ST_ACCEL_4_BDU_ADDR 0x21 -#define ST_ACCEL_4_BDU_MASK 0x40 -#define ST_ACCEL_4_DRDY_IRQ_ADDR 0x21 -#define ST_ACCEL_4_DRDY_IRQ_INT1_MASK 0x04 -#define ST_ACCEL_4_MULTIREAD_BIT true - -/* CUSTOM VALUES FOR SENSOR 5 */ -#define ST_ACCEL_5_WAI_EXP 0x3b -#define ST_ACCEL_5_ODR_ADDR 0x20 -#define ST_ACCEL_5_ODR_MASK 0x80 -#define ST_ACCEL_5_ODR_AVL_100HZ_VAL 0x00 -#define ST_ACCEL_5_ODR_AVL_400HZ_VAL 0x01 -#define ST_ACCEL_5_PW_ADDR 0x20 -#define ST_ACCEL_5_PW_MASK 0x40 -#define ST_ACCEL_5_FS_ADDR 0x20 -#define ST_ACCEL_5_FS_MASK 0x20 -#define ST_ACCEL_5_FS_AVL_2_VAL 0X00 -#define ST_ACCEL_5_FS_AVL_8_VAL 0X01 -/* TODO: check these resulting gain settings, these are not in the datsheet */ -#define ST_ACCEL_5_FS_AVL_2_GAIN IIO_G_TO_M_S_2(18000) -#define ST_ACCEL_5_FS_AVL_8_GAIN IIO_G_TO_M_S_2(72000) -#define ST_ACCEL_5_DRDY_IRQ_ADDR 0x22 -#define ST_ACCEL_5_DRDY_IRQ_INT1_MASK 0x04 -#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK 0x20 -#define ST_ACCEL_5_IHL_IRQ_ADDR 0x22 -#define ST_ACCEL_5_IHL_IRQ_MASK 0x80 -#define ST_ACCEL_5_OD_IRQ_ADDR 0x22 -#define ST_ACCEL_5_OD_IRQ_MASK 0x40 -#define ST_ACCEL_5_IG1_EN_ADDR 0x21 -#define ST_ACCEL_5_IG1_EN_MASK 0x08 -#define ST_ACCEL_5_MULTIREAD_BIT false - -/* CUSTOM VALUES FOR SENSOR 6 */ -#define ST_ACCEL_6_WAI_EXP 0x32 -#define ST_ACCEL_6_ODR_ADDR 0x20 -#define ST_ACCEL_6_ODR_MASK 0x18 -#define ST_ACCEL_6_ODR_AVL_50HZ_VAL 0x00 -#define ST_ACCEL_6_ODR_AVL_100HZ_VAL 0x01 -#define ST_ACCEL_6_ODR_AVL_400HZ_VAL 0x02 -#define ST_ACCEL_6_ODR_AVL_1000HZ_VAL 0x03 -#define ST_ACCEL_6_PW_ADDR 0x20 -#define ST_ACCEL_6_PW_MASK 0x20 -#define ST_ACCEL_6_FS_ADDR 0x23 -#define ST_ACCEL_6_FS_MASK 0x30 -#define ST_ACCEL_6_FS_AVL_100_VAL 0x00 -#define ST_ACCEL_6_FS_AVL_200_VAL 0x01 -#define ST_ACCEL_6_FS_AVL_400_VAL 0x03 -#define ST_ACCEL_6_FS_AVL_100_GAIN IIO_G_TO_M_S_2(49000) -#define ST_ACCEL_6_FS_AVL_200_GAIN IIO_G_TO_M_S_2(98000) -#define ST_ACCEL_6_FS_AVL_400_GAIN IIO_G_TO_M_S_2(195000) -#define ST_ACCEL_6_BDU_ADDR 0x23 -#define ST_ACCEL_6_BDU_MASK 0x80 -#define ST_ACCEL_6_DRDY_IRQ_ADDR 0x22 -#define ST_ACCEL_6_DRDY_IRQ_INT1_MASK 0x02 -#define ST_ACCEL_6_DRDY_IRQ_INT2_MASK 0x10 -#define ST_ACCEL_6_IHL_IRQ_ADDR 0x22 -#define ST_ACCEL_6_IHL_IRQ_MASK 0x80 -#define ST_ACCEL_6_MULTIREAD_BIT true - -/* CUSTOM VALUES FOR SENSOR 7 */ -#define ST_ACCEL_7_ODR_ADDR 0x20 -#define ST_ACCEL_7_ODR_MASK 0x30 -#define ST_ACCEL_7_ODR_AVL_280HZ_VAL 0x00 -#define ST_ACCEL_7_ODR_AVL_560HZ_VAL 0x01 -#define ST_ACCEL_7_ODR_AVL_1120HZ_VAL 0x02 -#define ST_ACCEL_7_ODR_AVL_4480HZ_VAL 0x03 -#define ST_ACCEL_7_PW_ADDR 0x20 -#define ST_ACCEL_7_PW_MASK 0xc0 -#define ST_ACCEL_7_FS_AVL_2_GAIN IIO_G_TO_M_S_2(488) -#define ST_ACCEL_7_BDU_ADDR 0x21 -#define ST_ACCEL_7_BDU_MASK 0x40 -#define ST_ACCEL_7_DRDY_IRQ_ADDR 0x21 -#define ST_ACCEL_7_DRDY_IRQ_INT1_MASK 0x04 -#define ST_ACCEL_7_MULTIREAD_BIT false - -/* CUSTOM VALUES FOR SENSOR 8 */ -#define ST_ACCEL_8_FS_AVL_2_GAIN IIO_G_TO_M_S_2(15600) -#define ST_ACCEL_8_FS_AVL_4_GAIN IIO_G_TO_M_S_2(31200) -#define ST_ACCEL_8_FS_AVL_8_GAIN IIO_G_TO_M_S_2(62500) -#define ST_ACCEL_8_FS_AVL_16_GAIN IIO_G_TO_M_S_2(187500) - static const struct iio_chan_spec st_accel_8bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -287,7 +93,7 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = { static const struct st_sensor_settings st_accel_sensors_settings[] = { { - .wai = ST_ACCEL_1_WAI_EXP, + .wai = 0x33, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3DH_ACCEL_DEV_NAME, @@ -300,22 +106,22 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { - .addr = ST_ACCEL_1_ODR_ADDR, - .mask = ST_ACCEL_1_ODR_MASK, + .addr = 0x20, + .mask = 0xf0, .odr_avl = { - { 1, ST_ACCEL_1_ODR_AVL_1HZ_VAL, }, - { 10, ST_ACCEL_1_ODR_AVL_10HZ_VAL, }, - { 25, ST_ACCEL_1_ODR_AVL_25HZ_VAL, }, - { 50, ST_ACCEL_1_ODR_AVL_50HZ_VAL, }, - { 100, ST_ACCEL_1_ODR_AVL_100HZ_VAL, }, - { 200, ST_ACCEL_1_ODR_AVL_200HZ_VAL, }, - { 400, ST_ACCEL_1_ODR_AVL_400HZ_VAL, }, - { 1600, ST_ACCEL_1_ODR_AVL_1600HZ_VAL, }, + { .hz = 1, .value = 0x01, }, + { .hz = 10, .value = 0x02, }, + { .hz = 25, .value = 0x03, }, + { .hz = 50, .value = 0x04, }, + { .hz = 100, .value = 0x05, }, + { .hz = 200, .value = 0x06, }, + { .hz = 400, .value = 0x07, }, + { .hz = 1600, .value = 0x08, }, }, }, .pw = { - .addr = ST_ACCEL_1_ODR_ADDR, - .mask = ST_ACCEL_1_ODR_MASK, + .addr = 0x20, + .mask = 0xf0, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .enable_axis = { @@ -323,48 +129,48 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_1_FS_ADDR, - .mask = ST_ACCEL_1_FS_MASK, + .addr = 0x23, + .mask = 0x30, .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .value = ST_ACCEL_1_FS_AVL_2_VAL, - .gain = ST_ACCEL_1_FS_AVL_2_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(1000), }, [1] = { .num = ST_ACCEL_FS_AVL_4G, - .value = ST_ACCEL_1_FS_AVL_4_VAL, - .gain = ST_ACCEL_1_FS_AVL_4_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(2000), }, [2] = { .num = ST_ACCEL_FS_AVL_8G, - .value = ST_ACCEL_1_FS_AVL_8_VAL, - .gain = ST_ACCEL_1_FS_AVL_8_GAIN, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(4000), }, [3] = { .num = ST_ACCEL_FS_AVL_16G, - .value = ST_ACCEL_1_FS_AVL_16_VAL, - .gain = ST_ACCEL_1_FS_AVL_16_GAIN, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(12000), }, }, }, .bdu = { - .addr = ST_ACCEL_1_BDU_ADDR, - .mask = ST_ACCEL_1_BDU_MASK, + .addr = 0x23, + .mask = 0x80, }, .drdy_irq = { - .addr = ST_ACCEL_1_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK, - .addr_ihl = ST_ACCEL_1_IHL_IRQ_ADDR, - .mask_ihl = ST_ACCEL_1_IHL_IRQ_MASK, + .addr = 0x22, + .mask_int1 = 0x10, + .mask_int2 = 0x08, + .addr_ihl = 0x25, + .mask_ihl = 0x02, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, - .multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT, + .multi_read_bit = true, .bootime = 2, }, { - .wai = ST_ACCEL_2_WAI_EXP, + .wai = 0x32, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DLH_ACCEL_DEV_NAME, @@ -374,18 +180,18 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { - .addr = ST_ACCEL_2_ODR_ADDR, - .mask = ST_ACCEL_2_ODR_MASK, + .addr = 0x20, + .mask = 0x18, .odr_avl = { - { 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, }, - { 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, }, - { 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, }, - { 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, }, + { .hz = 50, .value = 0x00, }, + { .hz = 100, .value = 0x01, }, + { .hz = 400, .value = 0x02, }, + { .hz = 1000, .value = 0x03, }, }, }, .pw = { - .addr = ST_ACCEL_2_PW_ADDR, - .mask = ST_ACCEL_2_PW_MASK, + .addr = 0x20, + .mask = 0xe0, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, @@ -394,69 +200,69 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_2_FS_ADDR, - .mask = ST_ACCEL_2_FS_MASK, + .addr = 0x23, + .mask = 0x30, .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .value = ST_ACCEL_2_FS_AVL_2_VAL, - .gain = ST_ACCEL_2_FS_AVL_2_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(1000), }, [1] = { .num = ST_ACCEL_FS_AVL_4G, - .value = ST_ACCEL_2_FS_AVL_4_VAL, - .gain = ST_ACCEL_2_FS_AVL_4_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(2000), }, [2] = { .num = ST_ACCEL_FS_AVL_8G, - .value = ST_ACCEL_2_FS_AVL_8_VAL, - .gain = ST_ACCEL_2_FS_AVL_8_GAIN, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(3900), }, }, }, .bdu = { - .addr = ST_ACCEL_2_BDU_ADDR, - .mask = ST_ACCEL_2_BDU_MASK, + .addr = 0x23, + .mask = 0x80, }, .drdy_irq = { - .addr = ST_ACCEL_2_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK, - .addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR, - .mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK, - .addr_od = ST_ACCEL_2_OD_IRQ_ADDR, - .mask_od = ST_ACCEL_2_OD_IRQ_MASK, + .addr = 0x22, + .mask_int1 = 0x02, + .mask_int2 = 0x10, + .addr_ihl = 0x22, + .mask_ihl = 0x80, + .addr_od = 0x22, + .mask_od = 0x40, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, - .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT, + .multi_read_bit = true, .bootime = 2, }, { - .wai = ST_ACCEL_3_WAI_EXP, + .wai = 0x40, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM330_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_16bit_channels, .odr = { - .addr = ST_ACCEL_3_ODR_ADDR, - .mask = ST_ACCEL_3_ODR_MASK, + .addr = 0x20, + .mask = 0xf0, .odr_avl = { - { 3, ST_ACCEL_3_ODR_AVL_3HZ_VAL }, - { 6, ST_ACCEL_3_ODR_AVL_6HZ_VAL, }, - { 12, ST_ACCEL_3_ODR_AVL_12HZ_VAL, }, - { 25, ST_ACCEL_3_ODR_AVL_25HZ_VAL, }, - { 50, ST_ACCEL_3_ODR_AVL_50HZ_VAL, }, - { 100, ST_ACCEL_3_ODR_AVL_100HZ_VAL, }, - { 200, ST_ACCEL_3_ODR_AVL_200HZ_VAL, }, - { 400, ST_ACCEL_3_ODR_AVL_400HZ_VAL, }, - { 800, ST_ACCEL_3_ODR_AVL_800HZ_VAL, }, - { 1600, ST_ACCEL_3_ODR_AVL_1600HZ_VAL, }, + { .hz = 3, .value = 0x01, }, + { .hz = 6, .value = 0x02, }, + { .hz = 12, .value = 0x03, }, + { .hz = 25, .value = 0x04, }, + { .hz = 50, .value = 0x05, }, + { .hz = 100, .value = 0x06, }, + { .hz = 200, .value = 0x07, }, + { .hz = 400, .value = 0x08, }, + { .hz = 800, .value = 0x09, }, + { .hz = 1600, .value = 0x0a, }, }, }, .pw = { - .addr = ST_ACCEL_3_ODR_ADDR, - .mask = ST_ACCEL_3_ODR_MASK, + .addr = 0x20, + .mask = 0xf0, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .enable_axis = { @@ -464,75 +270,75 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_3_FS_ADDR, - .mask = ST_ACCEL_3_FS_MASK, + .addr = 0x24, + .mask = 0x38, .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .value = ST_ACCEL_3_FS_AVL_2_VAL, - .gain = ST_ACCEL_3_FS_AVL_2_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(61), }, [1] = { .num = ST_ACCEL_FS_AVL_4G, - .value = ST_ACCEL_3_FS_AVL_4_VAL, - .gain = ST_ACCEL_3_FS_AVL_4_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(122), }, [2] = { .num = ST_ACCEL_FS_AVL_6G, - .value = ST_ACCEL_3_FS_AVL_6_VAL, - .gain = ST_ACCEL_3_FS_AVL_6_GAIN, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(183), }, [3] = { .num = ST_ACCEL_FS_AVL_8G, - .value = ST_ACCEL_3_FS_AVL_8_VAL, - .gain = ST_ACCEL_3_FS_AVL_8_GAIN, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(244), }, [4] = { .num = ST_ACCEL_FS_AVL_16G, - .value = ST_ACCEL_3_FS_AVL_16_VAL, - .gain = ST_ACCEL_3_FS_AVL_16_GAIN, + .value = 0x04, + .gain = IIO_G_TO_M_S_2(732), }, }, }, .bdu = { - .addr = ST_ACCEL_3_BDU_ADDR, - .mask = ST_ACCEL_3_BDU_MASK, + .addr = 0x20, + .mask = 0x08, }, .drdy_irq = { - .addr = ST_ACCEL_3_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK, - .addr_ihl = ST_ACCEL_3_IHL_IRQ_ADDR, - .mask_ihl = ST_ACCEL_3_IHL_IRQ_MASK, + .addr = 0x23, + .mask_int1 = 0x80, + .mask_int2 = 0x00, + .addr_ihl = 0x23, + .mask_ihl = 0x40, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, .ig1 = { - .en_addr = ST_ACCEL_3_IG1_EN_ADDR, - .en_mask = ST_ACCEL_3_IG1_EN_MASK, + .en_addr = 0x23, + .en_mask = 0x08, }, }, - .multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT, + .multi_read_bit = false, .bootime = 2, }, { - .wai = ST_ACCEL_4_WAI_EXP, + .wai = 0x3a, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3LV02DL_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { - .addr = ST_ACCEL_4_ODR_ADDR, - .mask = ST_ACCEL_4_ODR_MASK, + .addr = 0x20, + .mask = 0x30, /* DF1 and DF0 */ .odr_avl = { - { 40, ST_ACCEL_4_ODR_AVL_40HZ_VAL }, - { 160, ST_ACCEL_4_ODR_AVL_160HZ_VAL, }, - { 640, ST_ACCEL_4_ODR_AVL_640HZ_VAL, }, - { 2560, ST_ACCEL_4_ODR_AVL_2560HZ_VAL, }, + { .hz = 40, .value = 0x00, }, + { .hz = 160, .value = 0x01, }, + { .hz = 640, .value = 0x02, }, + { .hz = 2560, .value = 0x03, }, }, }, .pw = { - .addr = ST_ACCEL_4_PW_ADDR, - .mask = ST_ACCEL_4_PW_MASK, + .addr = 0x20, + .mask = 0xc0, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, @@ -541,51 +347,51 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_4_FS_ADDR, - .mask = ST_ACCEL_4_FS_MASK, + .addr = 0x21, + .mask = 0x80, .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .value = ST_ACCEL_4_FS_AVL_2_VAL, - .gain = ST_ACCEL_4_FS_AVL_2_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(1024), }, [1] = { .num = ST_ACCEL_FS_AVL_6G, - .value = ST_ACCEL_4_FS_AVL_6_VAL, - .gain = ST_ACCEL_4_FS_AVL_6_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(340), }, }, }, .bdu = { - .addr = ST_ACCEL_4_BDU_ADDR, - .mask = ST_ACCEL_4_BDU_MASK, + .addr = 0x21, + .mask = 0x40, }, .drdy_irq = { - .addr = ST_ACCEL_4_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_4_DRDY_IRQ_INT1_MASK, + .addr = 0x21, + .mask_int1 = 0x04, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, - .multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT, + .multi_read_bit = true, .bootime = 2, /* guess */ }, { - .wai = ST_ACCEL_5_WAI_EXP, + .wai = 0x3b, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DL_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_8bit_channels, .odr = { - .addr = ST_ACCEL_5_ODR_ADDR, - .mask = ST_ACCEL_5_ODR_MASK, + .addr = 0x20, + .mask = 0x80, .odr_avl = { - { 100, ST_ACCEL_5_ODR_AVL_100HZ_VAL }, - { 400, ST_ACCEL_5_ODR_AVL_400HZ_VAL, }, + { .hz = 100, .value = 0x00, }, + { .hz = 400, .value = 0x01, }, }, }, .pw = { - .addr = ST_ACCEL_5_PW_ADDR, - .mask = ST_ACCEL_5_PW_MASK, + .addr = 0x20, + .mask = 0x40, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, @@ -594,54 +400,58 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_5_FS_ADDR, - .mask = ST_ACCEL_5_FS_MASK, + .addr = 0x20, + .mask = 0x20, + /* + * TODO: check these resulting gain settings, these are + * not in the datsheet + */ .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .value = ST_ACCEL_5_FS_AVL_2_VAL, - .gain = ST_ACCEL_5_FS_AVL_2_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(18000), }, [1] = { .num = ST_ACCEL_FS_AVL_8G, - .value = ST_ACCEL_5_FS_AVL_8_VAL, - .gain = ST_ACCEL_5_FS_AVL_8_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(72000), }, }, }, .drdy_irq = { - .addr = ST_ACCEL_5_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_5_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK, - .addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR, - .mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK, - .addr_od = ST_ACCEL_5_OD_IRQ_ADDR, - .mask_od = ST_ACCEL_5_OD_IRQ_MASK, + .addr = 0x22, + .mask_int1 = 0x04, + .mask_int2 = 0x20, + .addr_ihl = 0x22, + .mask_ihl = 0x80, + .addr_od = 0x22, + .mask_od = 0x40, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, - .multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT, + .multi_read_bit = false, .bootime = 2, /* guess */ }, { - .wai = ST_ACCEL_6_WAI_EXP, + .wai = 0x32, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = H3LIS331DL_DRIVER_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { - .addr = ST_ACCEL_6_ODR_ADDR, - .mask = ST_ACCEL_6_ODR_MASK, + .addr = 0x20, + .mask = 0x18, .odr_avl = { - { 50, ST_ACCEL_6_ODR_AVL_50HZ_VAL }, - { 100, ST_ACCEL_6_ODR_AVL_100HZ_VAL, }, - { 400, ST_ACCEL_6_ODR_AVL_400HZ_VAL, }, - { 1000, ST_ACCEL_6_ODR_AVL_1000HZ_VAL, }, + { .hz = 50, .value = 0x00, }, + { .hz = 100, .value = 0x01, }, + { .hz = 400, .value = 0x02, }, + { .hz = 1000, .value = 0x03, }, }, }, .pw = { - .addr = ST_ACCEL_6_PW_ADDR, - .mask = ST_ACCEL_6_PW_MASK, + .addr = 0x20, + .mask = 0x20, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, @@ -650,38 +460,38 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_6_FS_ADDR, - .mask = ST_ACCEL_6_FS_MASK, + .addr = 0x23, + .mask = 0x30, .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_100G, - .value = ST_ACCEL_6_FS_AVL_100_VAL, - .gain = ST_ACCEL_6_FS_AVL_100_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(49000), }, [1] = { .num = ST_ACCEL_FS_AVL_200G, - .value = ST_ACCEL_6_FS_AVL_200_VAL, - .gain = ST_ACCEL_6_FS_AVL_200_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(98000), }, [2] = { .num = ST_ACCEL_FS_AVL_400G, - .value = ST_ACCEL_6_FS_AVL_400_VAL, - .gain = ST_ACCEL_6_FS_AVL_400_GAIN, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(195000), }, }, }, .bdu = { - .addr = ST_ACCEL_6_BDU_ADDR, - .mask = ST_ACCEL_6_BDU_MASK, + .addr = 0x23, + .mask = 0x80, }, .drdy_irq = { - .addr = ST_ACCEL_6_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_6_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_ACCEL_6_DRDY_IRQ_INT2_MASK, - .addr_ihl = ST_ACCEL_6_IHL_IRQ_ADDR, - .mask_ihl = ST_ACCEL_6_IHL_IRQ_MASK, + .addr = 0x22, + .mask_int1 = 0x02, + .mask_int2 = 0x10, + .addr_ihl = 0x22, + .mask_ihl = 0x80, }, - .multi_read_bit = ST_ACCEL_6_MULTIREAD_BIT, + .multi_read_bit = true, .bootime = 2, }, { @@ -691,18 +501,18 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { - .addr = ST_ACCEL_7_ODR_ADDR, - .mask = ST_ACCEL_7_ODR_MASK, + .addr = 0x20, + .mask = 0x30, .odr_avl = { - { 280, ST_ACCEL_7_ODR_AVL_280HZ_VAL, }, - { 560, ST_ACCEL_7_ODR_AVL_560HZ_VAL, }, - { 1120, ST_ACCEL_7_ODR_AVL_1120HZ_VAL, }, - { 4480, ST_ACCEL_7_ODR_AVL_4480HZ_VAL, }, + { .hz = 280, .value = 0x00, }, + { .hz = 560, .value = 0x01, }, + { .hz = 1120, .value = 0x02, }, + { .hz = 4480, .value = 0x03, }, }, }, .pw = { - .addr = ST_ACCEL_7_PW_ADDR, - .mask = ST_ACCEL_7_PW_MASK, + .addr = 0x20, + .mask = 0xc0, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, @@ -714,7 +524,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .gain = ST_ACCEL_7_FS_AVL_2_GAIN, + .gain = IIO_G_TO_M_S_2(488), }, }, }, @@ -725,37 +535,37 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .bdu = { }, .drdy_irq = { - .addr = ST_ACCEL_7_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_7_DRDY_IRQ_INT1_MASK, + .addr = 0x21, + .mask_int1 = 0x04, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, - .multi_read_bit = ST_ACCEL_7_MULTIREAD_BIT, + .multi_read_bit = false, .bootime = 2, }, { - .wai = ST_ACCEL_1_WAI_EXP, + .wai = 0x33, .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LNG2DM_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_8bit_channels, .odr = { - .addr = ST_ACCEL_1_ODR_ADDR, - .mask = ST_ACCEL_1_ODR_MASK, + .addr = 0x20, + .mask = 0xf0, .odr_avl = { - { 1, ST_ACCEL_1_ODR_AVL_1HZ_VAL, }, - { 10, ST_ACCEL_1_ODR_AVL_10HZ_VAL, }, - { 25, ST_ACCEL_1_ODR_AVL_25HZ_VAL, }, - { 50, ST_ACCEL_1_ODR_AVL_50HZ_VAL, }, - { 100, ST_ACCEL_1_ODR_AVL_100HZ_VAL, }, - { 200, ST_ACCEL_1_ODR_AVL_200HZ_VAL, }, - { 400, ST_ACCEL_1_ODR_AVL_400HZ_VAL, }, - { 1600, ST_ACCEL_1_ODR_AVL_1600HZ_VAL, }, + { .hz = 1, .value = 0x01, }, + { .hz = 10, .value = 0x02, }, + { .hz = 25, .value = 0x03, }, + { .hz = 50, .value = 0x04, }, + { .hz = 100, .value = 0x05, }, + { .hz = 200, .value = 0x06, }, + { .hz = 400, .value = 0x07, }, + { .hz = 1600, .value = 0x08, }, }, }, .pw = { - .addr = ST_ACCEL_1_ODR_ADDR, - .mask = ST_ACCEL_1_ODR_MASK, + .addr = 0x20, + .mask = 0xf0, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .enable_axis = { @@ -763,40 +573,40 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask = ST_SENSORS_DEFAULT_AXIS_MASK, }, .fs = { - .addr = ST_ACCEL_1_FS_ADDR, - .mask = ST_ACCEL_1_FS_MASK, + .addr = 0x23, + .mask = 0x30, .fs_avl = { [0] = { .num = ST_ACCEL_FS_AVL_2G, - .value = ST_ACCEL_1_FS_AVL_2_VAL, - .gain = ST_ACCEL_8_FS_AVL_2_GAIN, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(15600), }, [1] = { .num = ST_ACCEL_FS_AVL_4G, - .value = ST_ACCEL_1_FS_AVL_4_VAL, - .gain = ST_ACCEL_8_FS_AVL_4_GAIN, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(31200), }, [2] = { .num = ST_ACCEL_FS_AVL_8G, - .value = ST_ACCEL_1_FS_AVL_8_VAL, - .gain = ST_ACCEL_8_FS_AVL_8_GAIN, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(62500), }, [3] = { .num = ST_ACCEL_FS_AVL_16G, - .value = ST_ACCEL_1_FS_AVL_16_VAL, - .gain = ST_ACCEL_8_FS_AVL_16_GAIN, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(187500), }, }, }, .drdy_irq = { - .addr = ST_ACCEL_1_DRDY_IRQ_ADDR, - .mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK, - .addr_ihl = ST_ACCEL_1_IHL_IRQ_ADDR, - .mask_ihl = ST_ACCEL_1_IHL_IRQ_MASK, + .addr = 0x22, + .mask_int1 = 0x10, + .mask_int2 = 0x08, + .addr_ihl = 0x25, + .mask_ihl = 0x02, .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, - .multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT, + .multi_read_bit = true, .bootime = 2, }, }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6bbee0b0dfff..38bc319904c4 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -441,6 +441,28 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +config STM32_ADC_CORE + tristate "STMicroelectronics STM32 adc core" + depends on ARCH_STM32 || COMPILE_TEST + depends on OF + depends on REGULATOR + help + Select this option to enable the core driver for STMicroelectronics + STM32 analog-to-digital converter (ADC). + + This driver can also be built as a module. If so, the module + will be called stm32-adc-core. + +config STM32_ADC + tristate "STMicroelectronics STM32 adc" + depends on STM32_ADC_CORE + help + Say yes here to build support for STMicroelectronics stm32 Analog + to Digital Converter (ADC). + + This driver can also be built as a module. If so, the module + will be called stm32-adc. + config STX104 tristate "Apex Embedded Systems STX104 driver" depends on X86 && ISA_BUS_API diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9391217648cb..d36c4be8d1fc 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -43,6 +43,8 @@ obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_STX104) += stx104.o +obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o +obj-$(CONFIG_STM32_ADC) += stm32-adc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c new file mode 100644 index 000000000000..4214b0cd6b1b --- /dev/null +++ b/drivers/iio/adc/stm32-adc-core.c @@ -0,0 +1,303 @@ +/* + * This file is part of STM32 ADC driver + * + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. + * + * Inspired from: fsl-imx25-tsadc + * + * License type: GPLv2 + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdesc.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include "stm32-adc-core.h" + +/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */ +#define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) +#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04) + +/* STM32F4_ADC_CSR - bit fields */ +#define STM32F4_EOC3 BIT(17) +#define STM32F4_EOC2 BIT(9) +#define STM32F4_EOC1 BIT(1) + +/* STM32F4_ADC_CCR - bit fields */ +#define STM32F4_ADC_ADCPRE_SHIFT 16 +#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16) + +/* STM32 F4 maximum analog clock rate (from datasheet) */ +#define STM32F4_ADC_MAX_CLK_RATE 36000000 + +/** + * struct stm32_adc_priv - stm32 ADC core private data + * @irq: irq for ADC block + * @domain: irq domain reference + * @aclk: clock reference for the analog circuitry + * @vref: regulator reference + * @common: common data for all ADC instances + */ +struct stm32_adc_priv { + int irq; + struct irq_domain *domain; + struct clk *aclk; + struct regulator *vref; + struct stm32_adc_common common; +}; + +static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) +{ + return container_of(com, struct stm32_adc_priv, common); +} + +/* STM32F4 ADC internal common clock prescaler division ratios */ +static int stm32f4_pclk_div[] = {2, 4, 6, 8}; + +/** + * stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler + * @priv: stm32 ADC core private data + * Select clock prescaler used for analog conversions, before using ADC. + */ +static int stm32f4_adc_clk_sel(struct platform_device *pdev, + struct stm32_adc_priv *priv) +{ + unsigned long rate; + u32 val; + int i; + + rate = clk_get_rate(priv->aclk); + for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { + if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE) + break; + } + if (i >= ARRAY_SIZE(stm32f4_pclk_div)) + return -EINVAL; + + val = readl_relaxed(priv->common.base + STM32F4_ADC_CCR); + val &= ~STM32F4_ADC_ADCPRE_MASK; + val |= i << STM32F4_ADC_ADCPRE_SHIFT; + writel_relaxed(val, priv->common.base + STM32F4_ADC_CCR); + + dev_dbg(&pdev->dev, "Using analog clock source at %ld kHz\n", + rate / (stm32f4_pclk_div[i] * 1000)); + + return 0; +} + +/* ADC common interrupt for all instances */ +static void stm32_adc_irq_handler(struct irq_desc *desc) +{ + struct stm32_adc_priv *priv = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 status; + + chained_irq_enter(chip, desc); + status = readl_relaxed(priv->common.base + STM32F4_ADC_CSR); + + if (status & STM32F4_EOC1) + generic_handle_irq(irq_find_mapping(priv->domain, 0)); + + if (status & STM32F4_EOC2) + generic_handle_irq(irq_find_mapping(priv->domain, 1)); + + if (status & STM32F4_EOC3) + generic_handle_irq(irq_find_mapping(priv->domain, 2)); + + chained_irq_exit(chip, desc); +}; + +static int stm32_adc_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_level_irq); + + return 0; +} + +static void stm32_adc_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops stm32_adc_domain_ops = { + .map = stm32_adc_domain_map, + .unmap = stm32_adc_domain_unmap, + .xlate = irq_domain_xlate_onecell, +}; + +static int stm32_adc_irq_probe(struct platform_device *pdev, + struct stm32_adc_priv *priv) +{ + struct device_node *np = pdev->dev.of_node; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + return priv->irq; + } + + priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, + &stm32_adc_domain_ops, + priv); + if (!priv->domain) { + dev_err(&pdev->dev, "Failed to add irq domain\n"); + return -ENOMEM; + } + + irq_set_chained_handler(priv->irq, stm32_adc_irq_handler); + irq_set_handler_data(priv->irq, priv); + + return 0; +} + +static void stm32_adc_irq_remove(struct platform_device *pdev, + struct stm32_adc_priv *priv) +{ + int hwirq; + + for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++) + irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); + irq_domain_remove(priv->domain); + irq_set_chained_handler(priv->irq, NULL); +} + +static int stm32_adc_probe(struct platform_device *pdev) +{ + struct stm32_adc_priv *priv; + struct device_node *np = pdev->dev.of_node; + struct resource *res; + int ret; + + if (!pdev->dev.of_node) + return -ENODEV; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->common.base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->common.base)) + return PTR_ERR(priv->common.base); + + priv->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(priv->vref)) { + ret = PTR_ERR(priv->vref); + dev_err(&pdev->dev, "vref get failed, %d\n", ret); + return ret; + } + + ret = regulator_enable(priv->vref); + if (ret < 0) { + dev_err(&pdev->dev, "vref enable failed\n"); + return ret; + } + + ret = regulator_get_voltage(priv->vref); + if (ret < 0) { + dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret); + goto err_regulator_disable; + } + priv->common.vref_mv = ret / 1000; + dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); + + priv->aclk = devm_clk_get(&pdev->dev, "adc"); + if (IS_ERR(priv->aclk)) { + ret = PTR_ERR(priv->aclk); + dev_err(&pdev->dev, "Can't get 'adc' clock\n"); + goto err_regulator_disable; + } + + ret = clk_prepare_enable(priv->aclk); + if (ret < 0) { + dev_err(&pdev->dev, "adc clk enable failed\n"); + goto err_regulator_disable; + } + + ret = stm32f4_adc_clk_sel(pdev, priv); + if (ret < 0) { + dev_err(&pdev->dev, "adc clk selection failed\n"); + goto err_clk_disable; + } + + ret = stm32_adc_irq_probe(pdev, priv); + if (ret < 0) + goto err_clk_disable; + + platform_set_drvdata(pdev, &priv->common); + + ret = of_platform_populate(np, NULL, NULL, &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to populate DT children\n"); + goto err_irq_remove; + } + + return 0; + +err_irq_remove: + stm32_adc_irq_remove(pdev, priv); + +err_clk_disable: + clk_disable_unprepare(priv->aclk); + +err_regulator_disable: + regulator_disable(priv->vref); + + return ret; +} + +static int stm32_adc_remove(struct platform_device *pdev) +{ + struct stm32_adc_common *common = platform_get_drvdata(pdev); + struct stm32_adc_priv *priv = to_stm32_adc_priv(common); + + of_platform_depopulate(&pdev->dev); + stm32_adc_irq_remove(pdev, priv); + clk_disable_unprepare(priv->aclk); + regulator_disable(priv->vref); + + return 0; +} + +static const struct of_device_id stm32_adc_of_match[] = { + { .compatible = "st,stm32f4-adc-core" }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_adc_of_match); + +static struct platform_driver stm32_adc_driver = { + .probe = stm32_adc_probe, + .remove = stm32_adc_remove, + .driver = { + .name = "stm32-adc-core", + .of_match_table = stm32_adc_of_match, + }, +}; +module_platform_driver(stm32_adc_driver); + +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 ADC core driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:stm32-adc-core"); diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h new file mode 100644 index 000000000000..081fa5f55015 --- /dev/null +++ b/drivers/iio/adc/stm32-adc-core.h @@ -0,0 +1,52 @@ +/* + * This file is part of STM32 ADC driver + * + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. + * + * License type: GPLv2 + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __STM32_ADC_H +#define __STM32_ADC_H + +/* + * STM32 - ADC global register map + * ________________________________________________________ + * | Offset | Register | + * -------------------------------------------------------- + * | 0x000 | Master ADC1 | + * -------------------------------------------------------- + * | 0x100 | Slave ADC2 | + * -------------------------------------------------------- + * | 0x200 | Slave ADC3 | + * -------------------------------------------------------- + * | 0x300 | Master & Slave common regs | + * -------------------------------------------------------- + */ +#define STM32_ADC_MAX_ADCS 3 +#define STM32_ADCX_COMN_OFFSET 0x300 + +/** + * struct stm32_adc_common - stm32 ADC driver common data (for all instances) + * @base: control registers base cpu addr + * @vref_mv: vref voltage (mv) + */ +struct stm32_adc_common { + void __iomem *base; + int vref_mv; +}; + +#endif diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c new file mode 100644 index 000000000000..5715e79f4935 --- /dev/null +++ b/drivers/iio/adc/stm32-adc.c @@ -0,0 +1,518 @@ +/* + * This file is part of STM32 ADC driver + * + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. + * + * License type: GPLv2 + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include "stm32-adc-core.h" + +/* STM32F4 - Registers for each ADC instance */ +#define STM32F4_ADC_SR 0x00 +#define STM32F4_ADC_CR1 0x04 +#define STM32F4_ADC_CR2 0x08 +#define STM32F4_ADC_SMPR1 0x0C +#define STM32F4_ADC_SMPR2 0x10 +#define STM32F4_ADC_HTR 0x24 +#define STM32F4_ADC_LTR 0x28 +#define STM32F4_ADC_SQR1 0x2C +#define STM32F4_ADC_SQR2 0x30 +#define STM32F4_ADC_SQR3 0x34 +#define STM32F4_ADC_JSQR 0x38 +#define STM32F4_ADC_JDR1 0x3C +#define STM32F4_ADC_JDR2 0x40 +#define STM32F4_ADC_JDR3 0x44 +#define STM32F4_ADC_JDR4 0x48 +#define STM32F4_ADC_DR 0x4C + +/* STM32F4_ADC_SR - bit fields */ +#define STM32F4_STRT BIT(4) +#define STM32F4_EOC BIT(1) + +/* STM32F4_ADC_CR1 - bit fields */ +#define STM32F4_SCAN BIT(8) +#define STM32F4_EOCIE BIT(5) + +/* STM32F4_ADC_CR2 - bit fields */ +#define STM32F4_SWSTART BIT(30) +#define STM32F4_EXTEN_MASK GENMASK(29, 28) +#define STM32F4_EOCS BIT(10) +#define STM32F4_ADON BIT(0) + +/* STM32F4_ADC_SQR1 - bit fields */ +#define STM32F4_L_SHIFT 20 +#define STM32F4_L_MASK GENMASK(23, 20) + +/* STM32F4_ADC_SQR3 - bit fields */ +#define STM32F4_SQ1_SHIFT 0 +#define STM32F4_SQ1_MASK GENMASK(4, 0) + +#define STM32_ADC_TIMEOUT_US 100000 +#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) + +/** + * struct stm32_adc - private data of each ADC IIO instance + * @common: reference to ADC block common data + * @offset: ADC instance register offset in ADC block + * @completion: end of single conversion completion + * @buffer: data buffer + * @clk: clock for this adc instance + * @irq: interrupt for this adc instance + * @lock: spinlock + */ +struct stm32_adc { + struct stm32_adc_common *common; + u32 offset; + struct completion completion; + u16 *buffer; + struct clk *clk; + int irq; + spinlock_t lock; /* interrupt lock */ +}; + +/** + * struct stm32_adc_chan_spec - specification of stm32 adc channel + * @type: IIO channel type + * @channel: channel number (single ended) + * @name: channel name (single ended) + */ +struct stm32_adc_chan_spec { + enum iio_chan_type type; + int channel; + const char *name; +}; + +/* Input definitions common for all STM32F4 instances */ +static const struct stm32_adc_chan_spec stm32f4_adc123_channels[] = { + { IIO_VOLTAGE, 0, "in0" }, + { IIO_VOLTAGE, 1, "in1" }, + { IIO_VOLTAGE, 2, "in2" }, + { IIO_VOLTAGE, 3, "in3" }, + { IIO_VOLTAGE, 4, "in4" }, + { IIO_VOLTAGE, 5, "in5" }, + { IIO_VOLTAGE, 6, "in6" }, + { IIO_VOLTAGE, 7, "in7" }, + { IIO_VOLTAGE, 8, "in8" }, + { IIO_VOLTAGE, 9, "in9" }, + { IIO_VOLTAGE, 10, "in10" }, + { IIO_VOLTAGE, 11, "in11" }, + { IIO_VOLTAGE, 12, "in12" }, + { IIO_VOLTAGE, 13, "in13" }, + { IIO_VOLTAGE, 14, "in14" }, + { IIO_VOLTAGE, 15, "in15" }, +}; + +/** + * STM32 ADC registers access routines + * @adc: stm32 adc instance + * @reg: reg offset in adc instance + * + * Note: All instances share same base, with 0x0, 0x100 or 0x200 offset resp. + * for adc1, adc2 and adc3. + */ +static u32 stm32_adc_readl(struct stm32_adc *adc, u32 reg) +{ + return readl_relaxed(adc->common->base + adc->offset + reg); +} + +static u16 stm32_adc_readw(struct stm32_adc *adc, u32 reg) +{ + return readw_relaxed(adc->common->base + adc->offset + reg); +} + +static void stm32_adc_writel(struct stm32_adc *adc, u32 reg, u32 val) +{ + writel_relaxed(val, adc->common->base + adc->offset + reg); +} + +static void stm32_adc_set_bits(struct stm32_adc *adc, u32 reg, u32 bits) +{ + unsigned long flags; + + spin_lock_irqsave(&adc->lock, flags); + stm32_adc_writel(adc, reg, stm32_adc_readl(adc, reg) | bits); + spin_unlock_irqrestore(&adc->lock, flags); +} + +static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits) +{ + unsigned long flags; + + spin_lock_irqsave(&adc->lock, flags); + stm32_adc_writel(adc, reg, stm32_adc_readl(adc, reg) & ~bits); + spin_unlock_irqrestore(&adc->lock, flags); +} + +/** + * stm32_adc_conv_irq_enable() - Enable end of conversion interrupt + * @adc: stm32 adc instance + */ +static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) +{ + stm32_adc_set_bits(adc, STM32F4_ADC_CR1, STM32F4_EOCIE); +}; + +/** + * stm32_adc_conv_irq_disable() - Disable end of conversion interrupt + * @adc: stm32 adc instance + */ +static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) +{ + stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_EOCIE); +} + +/** + * stm32_adc_start_conv() - Start conversions for regular channels. + * @adc: stm32 adc instance + */ +static void stm32_adc_start_conv(struct stm32_adc *adc) +{ + stm32_adc_set_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); + stm32_adc_set_bits(adc, STM32F4_ADC_CR2, STM32F4_EOCS | STM32F4_ADON); + + /* Wait for Power-up time (tSTAB from datasheet) */ + usleep_range(2, 3); + + /* Software start ? (e.g. trigger detection disabled ?) */ + if (!(stm32_adc_readl(adc, STM32F4_ADC_CR2) & STM32F4_EXTEN_MASK)) + stm32_adc_set_bits(adc, STM32F4_ADC_CR2, STM32F4_SWSTART); +} + +static void stm32_adc_stop_conv(struct stm32_adc *adc) +{ + stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_EXTEN_MASK); + stm32_adc_clr_bits(adc, STM32F4_ADC_SR, STM32F4_STRT); + + stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); + stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_ADON); +} + +/** + * stm32_adc_single_conv() - Performs a single conversion + * @indio_dev: IIO device + * @chan: IIO channel + * @res: conversion result + * + * The function performs a single conversion on a given channel: + * - Program sequencer with one channel (e.g. in SQ1 with len = 1) + * - Use SW trigger + * - Start conversion, then wait for interrupt completion. + */ +static int stm32_adc_single_conv(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *res) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + long timeout; + u32 val; + u16 result; + int ret; + + reinit_completion(&adc->completion); + + adc->buffer = &result; + + /* Program chan number in regular sequence */ + val = stm32_adc_readl(adc, STM32F4_ADC_SQR3); + val &= ~STM32F4_SQ1_MASK; + val |= chan->channel << STM32F4_SQ1_SHIFT; + stm32_adc_writel(adc, STM32F4_ADC_SQR3, val); + + /* Set regular sequence len (0 for 1 conversion) */ + stm32_adc_clr_bits(adc, STM32F4_ADC_SQR1, STM32F4_L_MASK); + + /* Trigger detection disabled (conversion can be launched in SW) */ + stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_EXTEN_MASK); + + stm32_adc_conv_irq_enable(adc); + + stm32_adc_start_conv(adc); + + timeout = wait_for_completion_interruptible_timeout( + &adc->completion, STM32_ADC_TIMEOUT); + if (timeout == 0) { + ret = -ETIMEDOUT; + } else if (timeout < 0) { + ret = timeout; + } else { + *res = result; + ret = IIO_VAL_INT; + } + + stm32_adc_stop_conv(adc); + + stm32_adc_conv_irq_disable(adc); + + return ret; +} + +static int stm32_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + if (chan->type == IIO_VOLTAGE) + ret = stm32_adc_single_conv(indio_dev, chan, val); + else + ret = -EINVAL; + iio_device_release_direct_mode(indio_dev); + return ret; + + case IIO_CHAN_INFO_SCALE: + *val = adc->common->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static irqreturn_t stm32_adc_isr(int irq, void *data) +{ + struct stm32_adc *adc = data; + u32 status = stm32_adc_readl(adc, STM32F4_ADC_SR); + + if (status & STM32F4_EOC) { + *adc->buffer = stm32_adc_readw(adc, STM32F4_ADC_DR); + complete(&adc->completion); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int stm32_adc_of_xlate(struct iio_dev *indio_dev, + const struct of_phandle_args *iiospec) +{ + int i; + + for (i = 0; i < indio_dev->num_channels; i++) + if (indio_dev->channels[i].channel == iiospec->args[0]) + return i; + + return -EINVAL; +} + +/** + * stm32_adc_debugfs_reg_access - read or write register value + * + * To read a value from an ADC register: + * echo [ADC reg offset] > direct_reg_access + * cat direct_reg_access + * + * To write a value in a ADC register: + * echo [ADC_reg_offset] [value] > direct_reg_access + */ +static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned reg, unsigned writeval, + unsigned *readval) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + + if (!readval) + stm32_adc_writel(adc, reg, writeval); + else + *readval = stm32_adc_readl(adc, reg); + + return 0; +} + +static const struct iio_info stm32_adc_iio_info = { + .read_raw = stm32_adc_read_raw, + .debugfs_reg_access = stm32_adc_debugfs_reg_access, + .of_xlate = stm32_adc_of_xlate, + .driver_module = THIS_MODULE, +}; + +static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, + struct iio_chan_spec *chan, + const struct stm32_adc_chan_spec *channel, + int scan_index) +{ + chan->type = channel->type; + chan->channel = channel->channel; + chan->datasheet_name = channel->name; + chan->scan_index = scan_index; + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->scan_type.sign = 'u'; + chan->scan_type.realbits = 12; + chan->scan_type.storagebits = 16; +} + +static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) +{ + struct device_node *node = indio_dev->dev.of_node; + struct property *prop; + const __be32 *cur; + struct iio_chan_spec *channels; + int scan_index = 0, num_channels; + u32 val; + + num_channels = of_property_count_u32_elems(node, "st,adc-channels"); + if (num_channels < 0 || + num_channels >= ARRAY_SIZE(stm32f4_adc123_channels)) { + dev_err(&indio_dev->dev, "Bad st,adc-channels?\n"); + return num_channels < 0 ? num_channels : -EINVAL; + } + + channels = devm_kcalloc(&indio_dev->dev, num_channels, + sizeof(struct iio_chan_spec), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) { + if (val >= ARRAY_SIZE(stm32f4_adc123_channels)) { + dev_err(&indio_dev->dev, "Invalid channel %d\n", val); + return -EINVAL; + } + stm32_adc_chan_init_one(indio_dev, &channels[scan_index], + &stm32f4_adc123_channels[val], + scan_index); + scan_index++; + } + + indio_dev->num_channels = scan_index; + indio_dev->channels = channels; + + return 0; +} + +static int stm32_adc_probe(struct platform_device *pdev) +{ + struct iio_dev *indio_dev; + struct stm32_adc *adc; + int ret; + + if (!pdev->dev.of_node) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->common = dev_get_drvdata(pdev->dev.parent); + spin_lock_init(&adc->lock); + init_completion(&adc->completion); + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &stm32_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + platform_set_drvdata(pdev, adc); + + ret = of_property_read_u32(pdev->dev.of_node, "reg", &adc->offset); + if (ret != 0) { + dev_err(&pdev->dev, "missing reg property\n"); + return -EINVAL; + } + + adc->irq = platform_get_irq(pdev, 0); + if (adc->irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + return adc->irq; + } + + ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr, + 0, pdev->name, adc); + if (ret) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + return ret; + } + + adc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(adc->clk)) { + dev_err(&pdev->dev, "Can't get clock\n"); + return PTR_ERR(adc->clk); + } + + ret = clk_prepare_enable(adc->clk); + if (ret < 0) { + dev_err(&pdev->dev, "clk enable failed\n"); + return ret; + } + + ret = stm32_adc_chan_of_init(indio_dev); + if (ret < 0) + goto err_clk_disable; + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "iio dev register failed\n"); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable_unprepare(adc->clk); + + return ret; +} + +static int stm32_adc_remove(struct platform_device *pdev) +{ + struct stm32_adc *adc = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + + iio_device_unregister(indio_dev); + clk_disable_unprepare(adc->clk); + + return 0; +} + +static const struct of_device_id stm32_adc_of_match[] = { + { .compatible = "st,stm32f4-adc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_adc_of_match); + +static struct platform_driver stm32_adc_driver = { + .probe = stm32_adc_probe, + .remove = stm32_adc_remove, + .driver = { + .name = "stm32-adc", + .of_match_table = stm32_adc_of_match, + }, +}; +module_platform_driver(stm32_adc_driver); + +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 ADC IIO driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:stm32-adc"); diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index 0b87f6adbb79..a78b6025c465 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -565,7 +565,7 @@ static ssize_t in_illuminance_lux_table_store(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); const unsigned int max_ints = TSL2583_MAX_LUX_TABLE_ENTRIES * 3; - int value[TSL2583_MAX_LUX_TABLE_ENTRIES * 3]; + int value[TSL2583_MAX_LUX_TABLE_ENTRIES * 3 + 1]; int ret = -EINVAL; unsigned int n; diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index d8a0c8da8db0..0e791b02ed4a 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -42,9 +42,17 @@ enum magn_3d_channel { MAGN_3D_CHANNEL_MAX, }; +struct common_attributes { + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; +}; + struct magn_3d_state { struct hid_sensor_hub_callbacks callbacks; - struct hid_sensor_common common_attributes; + struct hid_sensor_common magn_flux_attributes; + struct hid_sensor_common rot_attributes; struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; /* dynamically sized array to hold sensor values */ @@ -52,10 +60,8 @@ struct magn_3d_state { /* array of pointers to sensor value */ u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX]; - int scale_pre_decml; - int scale_post_decml; - int scale_precision; - int value_offset; + struct common_attributes magn_flux_attr; + struct common_attributes rot_attr; }; static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { @@ -162,41 +168,74 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, *val2 = 0; switch (mask) { case 0: - hid_sensor_power_state(&magn_state->common_attributes, true); + hid_sensor_power_state(&magn_state->magn_flux_attributes, true); report_id = magn_state->magn[chan->address].report_id; address = magn_3d_addresses[chan->address]; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( - magn_state->common_attributes.hsdev, + magn_state->magn_flux_attributes.hsdev, HID_USAGE_SENSOR_COMPASS_3D, address, report_id, SENSOR_HUB_SYNC); else { *val = 0; - hid_sensor_power_state(&magn_state->common_attributes, - false); + hid_sensor_power_state( + &magn_state->magn_flux_attributes, + false); return -EINVAL; } - hid_sensor_power_state(&magn_state->common_attributes, false); + hid_sensor_power_state(&magn_state->magn_flux_attributes, + false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = magn_state->scale_pre_decml; - *val2 = magn_state->scale_post_decml; - ret_type = magn_state->scale_precision; + switch (chan->type) { + case IIO_MAGN: + *val = magn_state->magn_flux_attr.scale_pre_decml; + *val2 = magn_state->magn_flux_attr.scale_post_decml; + ret_type = magn_state->magn_flux_attr.scale_precision; + break; + case IIO_ROT: + *val = magn_state->rot_attr.scale_pre_decml; + *val2 = magn_state->rot_attr.scale_post_decml; + ret_type = magn_state->rot_attr.scale_precision; + break; + default: + ret_type = -EINVAL; + } break; case IIO_CHAN_INFO_OFFSET: - *val = magn_state->value_offset; - ret_type = IIO_VAL_INT; + switch (chan->type) { + case IIO_MAGN: + *val = magn_state->magn_flux_attr.value_offset; + ret_type = IIO_VAL_INT; + break; + case IIO_ROT: + *val = magn_state->rot_attr.value_offset; + ret_type = IIO_VAL_INT; + break; + default: + ret_type = -EINVAL; + } break; case IIO_CHAN_INFO_SAMP_FREQ: ret_type = hid_sensor_read_samp_freq_value( - &magn_state->common_attributes, val, val2); + &magn_state->magn_flux_attributes, val, val2); break; case IIO_CHAN_INFO_HYSTERESIS: - ret_type = hid_sensor_read_raw_hyst_value( - &magn_state->common_attributes, val, val2); + switch (chan->type) { + case IIO_MAGN: + ret_type = hid_sensor_read_raw_hyst_value( + &magn_state->magn_flux_attributes, val, val2); + break; + case IIO_ROT: + ret_type = hid_sensor_read_raw_hyst_value( + &magn_state->rot_attributes, val, val2); + break; + default: + ret_type = -EINVAL; + } break; default: ret_type = -EINVAL; @@ -219,11 +258,21 @@ static int magn_3d_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: ret = hid_sensor_write_samp_freq_value( - &magn_state->common_attributes, val, val2); + &magn_state->magn_flux_attributes, val, val2); break; case IIO_CHAN_INFO_HYSTERESIS: - ret = hid_sensor_write_raw_hyst_value( - &magn_state->common_attributes, val, val2); + switch (chan->type) { + case IIO_MAGN: + ret = hid_sensor_write_raw_hyst_value( + &magn_state->magn_flux_attributes, val, val2); + break; + case IIO_ROT: + ret = hid_sensor_write_raw_hyst_value( + &magn_state->rot_attributes, val, val2); + break; + default: + ret = -EINVAL; + } break; default: ret = -EINVAL; @@ -254,7 +303,7 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, struct magn_3d_state *magn_state = iio_priv(indio_dev); dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); - if (atomic_read(&magn_state->common_attributes.data_ready)) + if (atomic_read(&magn_state->magn_flux_attributes.data_ready)) hid_sensor_push_data(indio_dev, magn_state->iio_vals); return 0; @@ -389,21 +438,48 @@ static int magn_3d_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", *chan_count); - st->scale_precision = hid_sensor_format_scale( + st->magn_flux_attr.scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_COMPASS_3D, &st->magn[CHANNEL_SCAN_INDEX_X], - &st->scale_pre_decml, &st->scale_post_decml); + &st->magn_flux_attr.scale_pre_decml, + &st->magn_flux_attr.scale_post_decml); + st->rot_attr.scale_precision + = hid_sensor_format_scale( + HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH, + &st->magn[CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP], + &st->rot_attr.scale_pre_decml, + &st->rot_attr.scale_post_decml); /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { + if (st->magn_flux_attributes.sensitivity.index < 0) { sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | HID_USAGE_SENSOR_DATA_ORIENTATION, - &st->common_attributes.sensitivity); + &st->magn_flux_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->magn_flux_attributes.sensitivity.index, + st->magn_flux_attributes.sensitivity.report_id); + } + if (st->magn_flux_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX, + &st->magn_flux_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->magn_flux_attributes.sensitivity.index, + st->magn_flux_attributes.sensitivity.report_id); + } + if (st->rot_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH, + &st->rot_attributes.sensitivity); dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); + st->rot_attributes.sensitivity.index, + st->rot_attributes.sensitivity.report_id); } return 0; @@ -428,16 +504,17 @@ static int hid_magn_3d_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); magn_state = iio_priv(indio_dev); - magn_state->common_attributes.hsdev = hsdev; - magn_state->common_attributes.pdev = pdev; + magn_state->magn_flux_attributes.hsdev = hsdev; + magn_state->magn_flux_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_COMPASS_3D, - &magn_state->common_attributes); + &magn_state->magn_flux_attributes); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; } + magn_state->rot_attributes = magn_state->magn_flux_attributes; ret = magn_3d_parse_report(pdev, hsdev, &channels, &chan_count, @@ -460,9 +537,9 @@ static int hid_magn_3d_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); return ret; } - atomic_set(&magn_state->common_attributes.data_ready, 0); + atomic_set(&magn_state->magn_flux_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &magn_state->common_attributes); + &magn_state->magn_flux_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); goto error_unreg_buffer_funcs; @@ -489,7 +566,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(&magn_state->common_attributes); + hid_sensor_remove_trigger(&magn_state->magn_flux_attributes); error_unreg_buffer_funcs: iio_triggered_buffer_cleanup(indio_dev); return ret; @@ -504,7 +581,7 @@ static int hid_magn_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(&magn_state->common_attributes); + hid_sensor_remove_trigger(&magn_state->magn_flux_attributes); iio_triggered_buffer_cleanup(indio_dev); return 0; |