Second set of IIO new device support, features and cleanup for the 4.14 cycle.
New device support: * ak8974 - support the AMI306. * st_magnetometer - add support for the LIS2MDL with bindings. * rockchip-saradc - add binding for rv1108 SoC (no driver change). * srf08 - add srf02 (i2c only) and srf10 support. * stm32-timer - support for the STM32H7 to existing driver. Features: * tools - move over to the tools buildsystem rather than hand rolling. - add an install section to the build. * ak8974 - use serial number to add device randomness. - add AMI306 calibration data output. * ccs811 - triggered buffer support. * srf08 - add a device tree table as the old style i2c probing is going away, - add triggered buffer support * st32-adc - add optional st,min-sample-time-nsecs binding to allow control of sampling against analog circuitry. * stm32-timer - add output compare triggers. * ti-ads1015 - add threshold event support. * ti-ads7950 - Allow use on ACPI platforms including providing a default reference voltage as there is no way to obtain this on ACPI currently. Cleanup and fixes: * ad7606 - fix an error return code in probe. * ads1015 - fix incorrect data rate setting update when capture in progress, - fix wrong scale information for the ADS1115, - make conversions work when CONFIG_PM is not set, - make sure we don't get a stale result after a runtime resume by ensuring we wait long enough, - avoid returning a false error form the buffer setup callbacks, - add enough wait time to get the correct conversion, - remove an unnecessary config register update, - add a helper to set conversion mode reducing repeated boilerplate, - use devm_iio_triggered_buffer_setup to simplify error and remove paths, - use iio_device_claim_direct_mode instead of opencoding the same. * ak8974 - mark the INT_CLEAR register as precious to prevent debugfs access. * apds9300 - constify the i2c_device_id. * at91-sama5 adc - add missing Kconfig dependency. * bma180 accel - constify the i2c_device_id. * rockchip_saradc - explicitly request exclusive reset control as part of the reset rework on going throughout the kernel. * st_accel - fix drdy configuration for a load of accelerometers that only have the int1 line. Fix is unimportant as presumably no deviec tree actually used the non existent hardware line. * st_pressure - fix drdy configuration for LPS22HB and LPS25H by dropping int2 support as they don't have this. Fix is unimportant as presumably no device tree actually used the non existent hardware line. * stm32-dac - explicitly request exclusive reset control (part of reset being reworked). * tsl2583 - constify the i2c_device_id. * xadc - coding style fixes. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAlmZpCcRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FohlmQ/6A9FAI0wPGeEQCXDiLtIAWI1/DByYsHDk P3U6sFS17y56KAQcLS34HVR5lLreHya3hsUmPl4gCsjXZsGWAinyXy74BNtBbPmx LtzVsyLdjBP3Nxl/OGgNWG+kiq7Op+uw0/OZohtEqzurG0142S6CVvxteFlmhQNH pLlmPGnwk6Z4GsasHma/f2FkDD8oRVgvQSP7dJ9HIwq49qQ76cT/+20X1xODHLGw qpXfQiLUFW8E1JBTDDcXZD3M23TWG4DZcVlNnWf8fja/bk4WaLBKqVrI9gGZpZsQ xXfrSDRwc216w6tzVWjsNV/M0ZuSdm/VCBeyQa17XQVNelkO4dVrCqFMLCh5i/t5 p4qhhV9mrbweIgDj++6c+4qMzWSAznWybAKMMlcucmwxHKefcrlgUniE03OzyPpG gpMS94enlVW8WpE/iYkxb/d6EqTM9CH2CJH6W4Ve/Xr4aQHkF5/P23k+nsW113of T1q1SCKegV9p7hIzqDqDmOQC7iNTcBcu+/7RYtkDn9jmmhiQAxwoPJZunkR1cxD8 hA04x5W9HuPFdbNRlH1MozClbyRUtk0L/XLTKwA9T0VyRUKV1P6Szcp9wYRw+6G8 QiA5NNrNPf17L6slLZ06N1auu6vO7BhTmYNKnd6VBO+vi7kF/FM2UdZGHof4WT/4 zPE/BO8IwTk= =b6g8 -----END PGP SIGNATURE----- Merge tag 'iio-for-4.14b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Second set of IIO new device support, features and cleanup for the 4.14 cycle. New device support: * ak8974 - support the AMI306. * st_magnetometer - add support for the LIS2MDL with bindings. * rockchip-saradc - add binding for rv1108 SoC (no driver change). * srf08 - add srf02 (i2c only) and srf10 support. * stm32-timer - support for the STM32H7 to existing driver. Features: * tools - move over to the tools buildsystem rather than hand rolling. - add an install section to the build. * ak8974 - use serial number to add device randomness. - add AMI306 calibration data output. * ccs811 - triggered buffer support. * srf08 - add a device tree table as the old style i2c probing is going away, - add triggered buffer support * st32-adc - add optional st,min-sample-time-nsecs binding to allow control of sampling against analog circuitry. * stm32-timer - add output compare triggers. * ti-ads1015 - add threshold event support. * ti-ads7950 - Allow use on ACPI platforms including providing a default reference voltage as there is no way to obtain this on ACPI currently. Cleanup and fixes: * ad7606 - fix an error return code in probe. * ads1015 - fix incorrect data rate setting update when capture in progress, - fix wrong scale information for the ADS1115, - make conversions work when CONFIG_PM is not set, - make sure we don't get a stale result after a runtime resume by ensuring we wait long enough, - avoid returning a false error form the buffer setup callbacks, - add enough wait time to get the correct conversion, - remove an unnecessary config register update, - add a helper to set conversion mode reducing repeated boilerplate, - use devm_iio_triggered_buffer_setup to simplify error and remove paths, - use iio_device_claim_direct_mode instead of opencoding the same. * ak8974 - mark the INT_CLEAR register as precious to prevent debugfs access. * apds9300 - constify the i2c_device_id. * at91-sama5 adc - add missing Kconfig dependency. * bma180 accel - constify the i2c_device_id. * rockchip_saradc - explicitly request exclusive reset control as part of the reset rework on going throughout the kernel. * st_accel - fix drdy configuration for a load of accelerometers that only have the int1 line. Fix is unimportant as presumably no deviec tree actually used the non existent hardware line. * st_pressure - fix drdy configuration for LPS22HB and LPS25H by dropping int2 support as they don't have this. Fix is unimportant as presumably no device tree actually used the non existent hardware line. * stm32-dac - explicitly request exclusive reset control (part of reset being reworked). * tsl2583 - constify the i2c_device_id. * xadc - coding style fixes.
This commit is contained in:
commit
5e47adb906
|
@ -6,6 +6,7 @@ Required properties:
|
|||
- "rockchip,rk3066-tsadc": for rk3036
|
||||
- "rockchip,rk3328-saradc", "rockchip,rk3399-saradc": for rk3328
|
||||
- "rockchip,rk3399-saradc": for rk3399
|
||||
- "rockchip,rv1108-saradc", "rockchip,rk3399-saradc": for rv1108
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
|
|
@ -74,6 +74,11 @@ Optional properties:
|
|||
* can be 6, 8, 10 or 12 on stm32f4
|
||||
* can be 8, 10, 12, 14 or 16 on stm32h7
|
||||
Default is maximum resolution if unset.
|
||||
- st,min-sample-time-nsecs: Minimum sampling time in nanoseconds.
|
||||
Depending on hardware (board) e.g. high/low analog input source impedance,
|
||||
fine tune of ADC sampling time may be recommended.
|
||||
This can be either one value or an array that matches 'st,adc-channels' list,
|
||||
to set sample time resp. for all channels, or independently for each channel.
|
||||
|
||||
Example:
|
||||
adc: adc@40012000 {
|
||||
|
|
|
@ -64,6 +64,7 @@ Magnetometers:
|
|||
- st,lsm303dlhc-magn
|
||||
- st,lsm303dlm-magn
|
||||
- st,lis3mdl-magn
|
||||
- st,lis2mdl
|
||||
|
||||
Pressure sensors:
|
||||
- st,lps001wp-press
|
||||
|
|
|
@ -4,7 +4,9 @@ Must be a sub-node of an STM32 Timers device tree node.
|
|||
See ../mfd/stm32-timers.txt for details about the parent node.
|
||||
|
||||
Required parameters:
|
||||
- compatible: Must be "st,stm32-timer-trigger".
|
||||
- compatible: Must be one of:
|
||||
"st,stm32-timer-trigger"
|
||||
"st,stm32h7-timer-trigger"
|
||||
- reg: Identify trigger hardware block.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -842,7 +842,7 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
|
|||
#define BMA180_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct i2c_device_id bma180_ids[] = {
|
||||
static const struct i2c_device_id bma180_ids[] = {
|
||||
{ "bma180", BMA180 },
|
||||
{ "bma250", BMA250 },
|
||||
{ }
|
||||
|
|
|
@ -161,7 +161,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.drdy_irq = {
|
||||
.addr = 0x22,
|
||||
.mask_int1 = 0x10,
|
||||
.mask_int2 = 0x08,
|
||||
.mask_int2 = 0x00,
|
||||
.addr_ihl = 0x25,
|
||||
.mask_ihl = 0x02,
|
||||
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
|
||||
|
@ -637,7 +637,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.drdy_irq = {
|
||||
.addr = 0x22,
|
||||
.mask_int1 = 0x10,
|
||||
.mask_int2 = 0x08,
|
||||
.mask_int2 = 0x00,
|
||||
.addr_ihl = 0x25,
|
||||
.mask_ihl = 0x02,
|
||||
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
|
||||
|
|
|
@ -158,6 +158,7 @@ config AT91_SAMA5D2_ADC
|
|||
tristate "Atmel AT91 SAMA5D2 ADC"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Atmel SAMA5D2 ADC which is
|
||||
available on SAMA5D2 SoC family.
|
||||
|
|
|
@ -240,7 +240,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
|||
* The reset should be an optional property, as it should work
|
||||
* with old devicetrees as well
|
||||
*/
|
||||
info->reset = devm_reset_control_get(&pdev->dev, "saradc-apb");
|
||||
info->reset = devm_reset_control_get_exclusive(&pdev->dev,
|
||||
"saradc-apb");
|
||||
if (IS_ERR(info->reset)) {
|
||||
ret = PTR_ERR(info->reset);
|
||||
if (ret != -ENOENT)
|
||||
|
|
|
@ -83,6 +83,8 @@
|
|||
#define STM32H7_ADC_IER 0x04
|
||||
#define STM32H7_ADC_CR 0x08
|
||||
#define STM32H7_ADC_CFGR 0x0C
|
||||
#define STM32H7_ADC_SMPR1 0x14
|
||||
#define STM32H7_ADC_SMPR2 0x18
|
||||
#define STM32H7_ADC_PCSEL 0x1C
|
||||
#define STM32H7_ADC_SQR1 0x30
|
||||
#define STM32H7_ADC_SQR2 0x34
|
||||
|
@ -151,6 +153,7 @@ enum stm32h7_adc_dmngt {
|
|||
#define STM32H7_BOOST_CLKRATE 20000000UL
|
||||
|
||||
#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */
|
||||
#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */
|
||||
#define STM32_ADC_TIMEOUT_US 100000
|
||||
#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
|
||||
|
||||
|
@ -227,6 +230,8 @@ struct stm32_adc_regs {
|
|||
* @exten: trigger control register & bitfield
|
||||
* @extsel: trigger selection register & bitfield
|
||||
* @res: resolution selection register & bitfield
|
||||
* @smpr: smpr1 & smpr2 registers offset array
|
||||
* @smp_bits: smpr1 & smpr2 index and bitfields
|
||||
*/
|
||||
struct stm32_adc_regspec {
|
||||
const u32 dr;
|
||||
|
@ -236,6 +241,8 @@ struct stm32_adc_regspec {
|
|||
const struct stm32_adc_regs exten;
|
||||
const struct stm32_adc_regs extsel;
|
||||
const struct stm32_adc_regs res;
|
||||
const u32 smpr[2];
|
||||
const struct stm32_adc_regs *smp_bits;
|
||||
};
|
||||
|
||||
struct stm32_adc;
|
||||
|
@ -251,6 +258,7 @@ struct stm32_adc;
|
|||
* @start_conv: routine to start conversions
|
||||
* @stop_conv: routine to stop conversions
|
||||
* @unprepare: optional unprepare routine (disable, power-down)
|
||||
* @smp_cycles: programmable sampling time (ADC clock cycles)
|
||||
*/
|
||||
struct stm32_adc_cfg {
|
||||
const struct stm32_adc_regspec *regs;
|
||||
|
@ -262,6 +270,7 @@ struct stm32_adc_cfg {
|
|||
void (*start_conv)(struct stm32_adc *, bool dma);
|
||||
void (*stop_conv)(struct stm32_adc *);
|
||||
void (*unprepare)(struct stm32_adc *);
|
||||
const unsigned int *smp_cycles;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -283,6 +292,7 @@ struct stm32_adc_cfg {
|
|||
* @rx_dma_buf: dma rx buffer bus address
|
||||
* @rx_buf_sz: dma rx buffer size
|
||||
* @pcsel bitmask to preselect channels on some devices
|
||||
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
|
||||
* @cal: optional calibration data on some devices
|
||||
*/
|
||||
struct stm32_adc {
|
||||
|
@ -303,6 +313,7 @@ struct stm32_adc {
|
|||
dma_addr_t rx_dma_buf;
|
||||
unsigned int rx_buf_sz;
|
||||
u32 pcsel;
|
||||
u32 smpr_val[2];
|
||||
struct stm32_adc_calib cal;
|
||||
};
|
||||
|
||||
|
@ -431,6 +442,39 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
|
|||
{}, /* sentinel */
|
||||
};
|
||||
|
||||
/**
|
||||
* stm32f4_smp_bits[] - describe sampling time register index & bit fields
|
||||
* Sorted so it can be indexed by channel number.
|
||||
*/
|
||||
static const struct stm32_adc_regs stm32f4_smp_bits[] = {
|
||||
/* STM32F4_ADC_SMPR2: smpr[] index, mask, shift for SMP0 to SMP9 */
|
||||
{ 1, GENMASK(2, 0), 0 },
|
||||
{ 1, GENMASK(5, 3), 3 },
|
||||
{ 1, GENMASK(8, 6), 6 },
|
||||
{ 1, GENMASK(11, 9), 9 },
|
||||
{ 1, GENMASK(14, 12), 12 },
|
||||
{ 1, GENMASK(17, 15), 15 },
|
||||
{ 1, GENMASK(20, 18), 18 },
|
||||
{ 1, GENMASK(23, 21), 21 },
|
||||
{ 1, GENMASK(26, 24), 24 },
|
||||
{ 1, GENMASK(29, 27), 27 },
|
||||
/* STM32F4_ADC_SMPR1, smpr[] index, mask, shift for SMP10 to SMP18 */
|
||||
{ 0, GENMASK(2, 0), 0 },
|
||||
{ 0, GENMASK(5, 3), 3 },
|
||||
{ 0, GENMASK(8, 6), 6 },
|
||||
{ 0, GENMASK(11, 9), 9 },
|
||||
{ 0, GENMASK(14, 12), 12 },
|
||||
{ 0, GENMASK(17, 15), 15 },
|
||||
{ 0, GENMASK(20, 18), 18 },
|
||||
{ 0, GENMASK(23, 21), 21 },
|
||||
{ 0, GENMASK(26, 24), 24 },
|
||||
};
|
||||
|
||||
/* STM32F4 programmable sampling time (ADC clock cycles) */
|
||||
static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
|
||||
3, 15, 28, 56, 84, 112, 144, 480,
|
||||
};
|
||||
|
||||
static const struct stm32_adc_regspec stm32f4_adc_regspec = {
|
||||
.dr = STM32F4_ADC_DR,
|
||||
.ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE },
|
||||
|
@ -440,6 +484,8 @@ static const struct stm32_adc_regspec stm32f4_adc_regspec = {
|
|||
.extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK,
|
||||
STM32F4_EXTSEL_SHIFT },
|
||||
.res = { STM32F4_ADC_CR1, STM32F4_RES_MASK, STM32F4_RES_SHIFT },
|
||||
.smpr = { STM32F4_ADC_SMPR1, STM32F4_ADC_SMPR2 },
|
||||
.smp_bits = stm32f4_smp_bits,
|
||||
};
|
||||
|
||||
static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = {
|
||||
|
@ -483,6 +529,40 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
|
|||
{},
|
||||
};
|
||||
|
||||
/**
|
||||
* stm32h7_smp_bits - describe sampling time register index & bit fields
|
||||
* Sorted so it can be indexed by channel number.
|
||||
*/
|
||||
static const struct stm32_adc_regs stm32h7_smp_bits[] = {
|
||||
/* STM32H7_ADC_SMPR1, smpr[] index, mask, shift for SMP0 to SMP9 */
|
||||
{ 0, GENMASK(2, 0), 0 },
|
||||
{ 0, GENMASK(5, 3), 3 },
|
||||
{ 0, GENMASK(8, 6), 6 },
|
||||
{ 0, GENMASK(11, 9), 9 },
|
||||
{ 0, GENMASK(14, 12), 12 },
|
||||
{ 0, GENMASK(17, 15), 15 },
|
||||
{ 0, GENMASK(20, 18), 18 },
|
||||
{ 0, GENMASK(23, 21), 21 },
|
||||
{ 0, GENMASK(26, 24), 24 },
|
||||
{ 0, GENMASK(29, 27), 27 },
|
||||
/* STM32H7_ADC_SMPR2, smpr[] index, mask, shift for SMP10 to SMP19 */
|
||||
{ 1, GENMASK(2, 0), 0 },
|
||||
{ 1, GENMASK(5, 3), 3 },
|
||||
{ 1, GENMASK(8, 6), 6 },
|
||||
{ 1, GENMASK(11, 9), 9 },
|
||||
{ 1, GENMASK(14, 12), 12 },
|
||||
{ 1, GENMASK(17, 15), 15 },
|
||||
{ 1, GENMASK(20, 18), 18 },
|
||||
{ 1, GENMASK(23, 21), 21 },
|
||||
{ 1, GENMASK(26, 24), 24 },
|
||||
{ 1, GENMASK(29, 27), 27 },
|
||||
};
|
||||
|
||||
/* STM32H7 programmable sampling time (ADC clock cycles, rounded down) */
|
||||
static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
|
||||
1, 2, 8, 16, 32, 64, 387, 810,
|
||||
};
|
||||
|
||||
static const struct stm32_adc_regspec stm32h7_adc_regspec = {
|
||||
.dr = STM32H7_ADC_DR,
|
||||
.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
|
||||
|
@ -492,6 +572,8 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
|
|||
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
|
||||
STM32H7_EXTSEL_SHIFT },
|
||||
.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
|
||||
.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
|
||||
.smp_bits = stm32h7_smp_bits,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -933,6 +1015,7 @@ static void stm32h7_adc_unprepare(struct stm32_adc *adc)
|
|||
* @scan_mask: channels to be converted
|
||||
*
|
||||
* Conversion sequence :
|
||||
* Apply sampling time settings for all channels.
|
||||
* Configure ADC scan sequence based on selected channels in scan_mask.
|
||||
* Add channels to SQR registers, from scan_mask LSB to MSB, then
|
||||
* program sequence len.
|
||||
|
@ -946,6 +1029,10 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
|
|||
u32 val, bit;
|
||||
int i = 0;
|
||||
|
||||
/* Apply sampling time settings */
|
||||
stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]);
|
||||
stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]);
|
||||
|
||||
for_each_set_bit(bit, scan_mask, indio_dev->masklength) {
|
||||
chan = indio_dev->channels + bit;
|
||||
/*
|
||||
|
@ -1079,6 +1166,7 @@ static const struct iio_enum stm32_adc_trig_pol = {
|
|||
* @res: conversion result
|
||||
*
|
||||
* The function performs a single conversion on a given channel:
|
||||
* - Apply sampling time settings
|
||||
* - Program sequencer with one channel (e.g. in SQ1 with len = 1)
|
||||
* - Use SW trigger
|
||||
* - Start conversion, then wait for interrupt completion.
|
||||
|
@ -1103,6 +1191,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Apply sampling time settings */
|
||||
stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]);
|
||||
stm32_adc_writel(adc, regs->smpr[1], adc->smpr_val[1]);
|
||||
|
||||
/* Program chan number in regular sequence (SQ1) */
|
||||
val = stm32_adc_readl(adc, regs->sqr[1].reg);
|
||||
val &= ~regs->sqr[1].mask;
|
||||
|
@ -1507,10 +1599,28 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
|
||||
{
|
||||
const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
|
||||
u32 period_ns, shift = smpr->shift, mask = smpr->mask;
|
||||
unsigned int smp, r = smpr->reg;
|
||||
|
||||
/* Determine sampling time (ADC clock cycles) */
|
||||
period_ns = NSEC_PER_SEC / adc->common->rate;
|
||||
for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++)
|
||||
if ((period_ns * adc->cfg->smp_cycles[smp]) >= smp_ns)
|
||||
break;
|
||||
if (smp > STM32_ADC_MAX_SMP)
|
||||
smp = STM32_ADC_MAX_SMP;
|
||||
|
||||
/* pre-build sampling time registers (e.g. smpr1, smpr2) */
|
||||
adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift);
|
||||
}
|
||||
|
||||
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)
|
||||
int scan_index, u32 smp)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
|
@ -1526,6 +1636,9 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
|
|||
chan->scan_type.storagebits = 16;
|
||||
chan->ext_info = stm32_adc_ext_info;
|
||||
|
||||
/* Prepare sampling time settings */
|
||||
stm32_adc_smpr_init(adc, chan->channel, smp);
|
||||
|
||||
/* pre-build selected channels mask */
|
||||
adc->pcsel |= BIT(chan->channel);
|
||||
}
|
||||
|
@ -1538,8 +1651,8 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
|
|||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
struct iio_chan_spec *channels;
|
||||
int scan_index = 0, num_channels;
|
||||
u32 val;
|
||||
int scan_index = 0, num_channels, ret;
|
||||
u32 val, smp = 0;
|
||||
|
||||
num_channels = of_property_count_u32_elems(node, "st,adc-channels");
|
||||
if (num_channels < 0 ||
|
||||
|
@ -1548,6 +1661,13 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
|
|||
return num_channels < 0 ? num_channels : -EINVAL;
|
||||
}
|
||||
|
||||
/* Optional sample time is provided either for each, or all channels */
|
||||
ret = of_property_count_u32_elems(node, "st,min-sample-time-nsecs");
|
||||
if (ret > 1 && ret != num_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
channels = devm_kcalloc(&indio_dev->dev, num_channels,
|
||||
sizeof(struct iio_chan_spec), GFP_KERNEL);
|
||||
if (!channels)
|
||||
|
@ -1558,9 +1678,19 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
|
|||
dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using of_property_read_u32_index(), smp value will only be
|
||||
* modified if valid u32 value can be decoded. This allows to
|
||||
* get either no value, 1 shared value for all indexes, or one
|
||||
* value per channel.
|
||||
*/
|
||||
of_property_read_u32_index(node, "st,min-sample-time-nsecs",
|
||||
scan_index, &smp);
|
||||
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
|
||||
&adc_info->channels[val],
|
||||
scan_index);
|
||||
scan_index, smp);
|
||||
scan_index++;
|
||||
}
|
||||
|
||||
|
@ -1755,6 +1885,7 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
|
|||
.clk_required = true,
|
||||
.start_conv = stm32f4_adc_start_conv,
|
||||
.stop_conv = stm32f4_adc_stop_conv,
|
||||
.smp_cycles = stm32f4_adc_smp_cycles,
|
||||
};
|
||||
|
||||
static const struct stm32_adc_cfg stm32h7_adc_cfg = {
|
||||
|
@ -1766,6 +1897,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
|
|||
.stop_conv = stm32h7_adc_stop_conv,
|
||||
.prepare = stm32h7_adc_prepare,
|
||||
.unprepare = stm32h7_adc_unprepare,
|
||||
.smp_cycles = stm32h7_adc_smp_cycles,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_adc_of_match[] = {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/types.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
@ -36,17 +38,38 @@
|
|||
|
||||
#define ADS1015_CONV_REG 0x00
|
||||
#define ADS1015_CFG_REG 0x01
|
||||
#define ADS1015_LO_THRESH_REG 0x02
|
||||
#define ADS1015_HI_THRESH_REG 0x03
|
||||
|
||||
#define ADS1015_CFG_COMP_QUE_SHIFT 0
|
||||
#define ADS1015_CFG_COMP_LAT_SHIFT 2
|
||||
#define ADS1015_CFG_COMP_POL_SHIFT 3
|
||||
#define ADS1015_CFG_COMP_MODE_SHIFT 4
|
||||
#define ADS1015_CFG_DR_SHIFT 5
|
||||
#define ADS1015_CFG_MOD_SHIFT 8
|
||||
#define ADS1015_CFG_PGA_SHIFT 9
|
||||
#define ADS1015_CFG_MUX_SHIFT 12
|
||||
|
||||
#define ADS1015_CFG_COMP_QUE_MASK GENMASK(1, 0)
|
||||
#define ADS1015_CFG_COMP_LAT_MASK BIT(2)
|
||||
#define ADS1015_CFG_COMP_POL_MASK BIT(2)
|
||||
#define ADS1015_CFG_COMP_MODE_MASK BIT(4)
|
||||
#define ADS1015_CFG_DR_MASK GENMASK(7, 5)
|
||||
#define ADS1015_CFG_MOD_MASK BIT(8)
|
||||
#define ADS1015_CFG_PGA_MASK GENMASK(11, 9)
|
||||
#define ADS1015_CFG_MUX_MASK GENMASK(14, 12)
|
||||
|
||||
/* Comparator queue and disable field */
|
||||
#define ADS1015_CFG_COMP_DISABLE 3
|
||||
|
||||
/* Comparator polarity field */
|
||||
#define ADS1015_CFG_COMP_POL_LOW 0
|
||||
#define ADS1015_CFG_COMP_POL_HIGH 1
|
||||
|
||||
/* Comparator mode field */
|
||||
#define ADS1015_CFG_COMP_MODE_TRAD 0
|
||||
#define ADS1015_CFG_COMP_MODE_WINDOW 1
|
||||
|
||||
/* device operating modes */
|
||||
#define ADS1015_CONTINUOUS 0
|
||||
#define ADS1015_SINGLESHOT 1
|
||||
|
@ -81,18 +104,36 @@ static const unsigned int ads1115_data_rate[] = {
|
|||
8, 16, 32, 64, 128, 250, 475, 860
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int scale;
|
||||
int uscale;
|
||||
} ads1015_scale[] = {
|
||||
{3, 0},
|
||||
{2, 0},
|
||||
{1, 0},
|
||||
{0, 500000},
|
||||
{0, 250000},
|
||||
{0, 125000},
|
||||
{0, 125000},
|
||||
{0, 125000},
|
||||
/*
|
||||
* Translation from PGA bits to full-scale positive and negative input voltage
|
||||
* range in mV
|
||||
*/
|
||||
static int ads1015_fullscale_range[] = {
|
||||
6144, 4096, 2048, 1024, 512, 256, 256, 256
|
||||
};
|
||||
|
||||
/*
|
||||
* Translation from COMP_QUE field value to the number of successive readings
|
||||
* exceed the threshold values before an interrupt is generated
|
||||
*/
|
||||
static const int ads1015_comp_queue[] = { 1, 2, 4 };
|
||||
|
||||
static const struct iio_event_spec ads1015_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_EITHER,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
|
||||
BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
};
|
||||
|
||||
#define ADS1015_V_CHAN(_chan, _addr) { \
|
||||
|
@ -111,6 +152,8 @@ static const struct {
|
|||
.shift = 4, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
.event_spec = ads1015_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ads1015_events), \
|
||||
.datasheet_name = "AIN"#_chan, \
|
||||
}
|
||||
|
||||
|
@ -132,6 +175,8 @@ static const struct {
|
|||
.shift = 4, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
.event_spec = ads1015_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ads1015_events), \
|
||||
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
|
||||
}
|
||||
|
||||
|
@ -150,6 +195,8 @@ static const struct {
|
|||
.storagebits = 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
.event_spec = ads1015_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ads1015_events), \
|
||||
.datasheet_name = "AIN"#_chan, \
|
||||
}
|
||||
|
||||
|
@ -170,9 +217,17 @@ static const struct {
|
|||
.storagebits = 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
.event_spec = ads1015_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ads1015_events), \
|
||||
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
|
||||
}
|
||||
|
||||
struct ads1015_thresh_data {
|
||||
unsigned int comp_queue;
|
||||
int high_thresh;
|
||||
int low_thresh;
|
||||
};
|
||||
|
||||
struct ads1015_data {
|
||||
struct regmap *regmap;
|
||||
/*
|
||||
|
@ -182,18 +237,54 @@ struct ads1015_data {
|
|||
struct mutex lock;
|
||||
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
|
||||
|
||||
unsigned int event_channel;
|
||||
unsigned int comp_mode;
|
||||
struct ads1015_thresh_data thresh_data[ADS1015_CHANNELS];
|
||||
|
||||
unsigned int *data_rate;
|
||||
/*
|
||||
* Set to true when the ADC is switched to the continuous-conversion
|
||||
* mode and exits from a power-down state. This flag is used to avoid
|
||||
* getting the stale result from the conversion register.
|
||||
*/
|
||||
bool conv_invalid;
|
||||
};
|
||||
|
||||
static bool ads1015_event_channel_enabled(struct ads1015_data *data)
|
||||
{
|
||||
return (data->event_channel != ADS1015_CHANNELS);
|
||||
}
|
||||
|
||||
static void ads1015_event_channel_enable(struct ads1015_data *data, int chan,
|
||||
int comp_mode)
|
||||
{
|
||||
WARN_ON(ads1015_event_channel_enabled(data));
|
||||
|
||||
data->event_channel = chan;
|
||||
data->comp_mode = comp_mode;
|
||||
}
|
||||
|
||||
static void ads1015_event_channel_disable(struct ads1015_data *data, int chan)
|
||||
{
|
||||
data->event_channel = ADS1015_CHANNELS;
|
||||
}
|
||||
|
||||
static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg == ADS1015_CFG_REG);
|
||||
switch (reg) {
|
||||
case ADS1015_CFG_REG:
|
||||
case ADS1015_LO_THRESH_REG:
|
||||
case ADS1015_HI_THRESH_REG:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config ads1015_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = ADS1015_CFG_REG,
|
||||
.max_register = ADS1015_HI_THRESH_REG,
|
||||
.writeable_reg = ads1015_is_writeable_reg,
|
||||
};
|
||||
|
||||
|
@ -235,33 +326,51 @@ static int ads1015_set_power_state(struct ads1015_data *data, bool on)
|
|||
ret = pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static
|
||||
int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
|
||||
{
|
||||
int ret, pga, dr, conv_time;
|
||||
bool change;
|
||||
unsigned int old, mask, cfg;
|
||||
|
||||
if (chan < 0 || chan >= ADS1015_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
pga = data->channel_data[chan].pga;
|
||||
dr = data->channel_data[chan].data_rate;
|
||||
|
||||
ret = regmap_update_bits_check(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MUX_MASK |
|
||||
ADS1015_CFG_PGA_MASK,
|
||||
chan << ADS1015_CFG_MUX_SHIFT |
|
||||
pga << ADS1015_CFG_PGA_SHIFT,
|
||||
&change);
|
||||
if (ret < 0)
|
||||
ret = regmap_read(data->regmap, ADS1015_CFG_REG, &old);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (change) {
|
||||
conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
|
||||
pga = data->channel_data[chan].pga;
|
||||
dr = data->channel_data[chan].data_rate;
|
||||
mask = ADS1015_CFG_MUX_MASK | ADS1015_CFG_PGA_MASK |
|
||||
ADS1015_CFG_DR_MASK;
|
||||
cfg = chan << ADS1015_CFG_MUX_SHIFT | pga << ADS1015_CFG_PGA_SHIFT |
|
||||
dr << ADS1015_CFG_DR_SHIFT;
|
||||
|
||||
if (ads1015_event_channel_enabled(data)) {
|
||||
mask |= ADS1015_CFG_COMP_QUE_MASK | ADS1015_CFG_COMP_MODE_MASK;
|
||||
cfg |= data->thresh_data[chan].comp_queue <<
|
||||
ADS1015_CFG_COMP_QUE_SHIFT |
|
||||
data->comp_mode <<
|
||||
ADS1015_CFG_COMP_MODE_SHIFT;
|
||||
}
|
||||
|
||||
cfg = (old & ~mask) | (cfg & mask);
|
||||
|
||||
ret = regmap_write(data->regmap, ADS1015_CFG_REG, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (old != cfg || data->conv_invalid) {
|
||||
int dr_old = (old & ADS1015_CFG_DR_MASK) >>
|
||||
ADS1015_CFG_DR_SHIFT;
|
||||
|
||||
conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr_old]);
|
||||
conv_time += DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
|
||||
usleep_range(conv_time, conv_time + 1);
|
||||
data->conv_invalid = false;
|
||||
}
|
||||
|
||||
return regmap_read(data->regmap, ADS1015_CONV_REG, val);
|
||||
|
@ -298,52 +407,36 @@ err:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ads1015_set_scale(struct ads1015_data *data, int chan,
|
||||
static int ads1015_set_scale(struct ads1015_data *data,
|
||||
struct iio_chan_spec const *chan,
|
||||
int scale, int uscale)
|
||||
{
|
||||
int i, ret, rindex = -1;
|
||||
int i;
|
||||
int fullscale = div_s64((scale * 1000000LL + uscale) <<
|
||||
(chan->scan_type.realbits - 1), 1000000);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_scale); i++)
|
||||
if (ads1015_scale[i].scale == scale &&
|
||||
ads1015_scale[i].uscale == uscale) {
|
||||
rindex = i;
|
||||
break;
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_fullscale_range); i++) {
|
||||
if (ads1015_fullscale_range[i] == fullscale) {
|
||||
data->channel_data[chan->address].pga = i;
|
||||
return 0;
|
||||
}
|
||||
if (rindex < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_PGA_MASK,
|
||||
rindex << ADS1015_CFG_PGA_SHIFT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->channel_data[chan].pga = rindex;
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
|
||||
{
|
||||
int i, ret, rindex = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++) {
|
||||
if (data->data_rate[i] == rate) {
|
||||
rindex = i;
|
||||
break;
|
||||
data->channel_data[chan].data_rate = i;
|
||||
return 0;
|
||||
}
|
||||
if (rindex < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_DR_MASK,
|
||||
rindex << ADS1015_CFG_DR_SHIFT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->channel_data[chan].data_rate = rindex;
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ads1015_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -353,41 +446,47 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
|
|||
int ret, idx;
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&data->lock);
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
int shift = chan->scan_type.shift;
|
||||
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
ret = -EBUSY;
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (ads1015_event_channel_enabled(data) &&
|
||||
data->event_channel != chan->address) {
|
||||
ret = -EBUSY;
|
||||
goto release_direct;
|
||||
}
|
||||
|
||||
ret = ads1015_set_power_state(data, true);
|
||||
if (ret < 0)
|
||||
break;
|
||||
goto release_direct;
|
||||
|
||||
ret = ads1015_get_adc_result(data, chan->address, val);
|
||||
if (ret < 0) {
|
||||
ads1015_set_power_state(data, false);
|
||||
break;
|
||||
goto release_direct;
|
||||
}
|
||||
|
||||
*val = sign_extend32(*val >> shift, 15 - shift);
|
||||
|
||||
ret = ads1015_set_power_state(data, false);
|
||||
if (ret < 0)
|
||||
break;
|
||||
goto release_direct;
|
||||
|
||||
ret = IIO_VAL_INT;
|
||||
release_direct:
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
break;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
idx = data->channel_data[chan->address].pga;
|
||||
*val = ads1015_scale[idx].scale;
|
||||
*val2 = ads1015_scale[idx].uscale;
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
*val = ads1015_fullscale_range[idx];
|
||||
*val2 = chan->scan_type.realbits - 1;
|
||||
ret = IIO_VAL_FRACTIONAL_LOG2;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
idx = data->channel_data[chan->address].data_rate;
|
||||
|
@ -399,7 +498,6 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
|
|||
break;
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -414,7 +512,7 @@ static int ads1015_write_raw(struct iio_dev *indio_dev,
|
|||
mutex_lock(&data->lock);
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = ads1015_set_scale(data, chan->address, val, val2);
|
||||
ret = ads1015_set_scale(data, chan, val, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = ads1015_set_data_rate(data, chan->address, val);
|
||||
|
@ -428,8 +526,254 @@ static int ads1015_write_raw(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ads1015_read_event(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, enum iio_event_info info, int *val,
|
||||
int *val2)
|
||||
{
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
unsigned int comp_queue;
|
||||
int period;
|
||||
int dr;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
*val = (dir == IIO_EV_DIR_RISING) ?
|
||||
data->thresh_data[chan->address].high_thresh :
|
||||
data->thresh_data[chan->address].low_thresh;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
dr = data->channel_data[chan->address].data_rate;
|
||||
comp_queue = data->thresh_data[chan->address].comp_queue;
|
||||
period = ads1015_comp_queue[comp_queue] *
|
||||
USEC_PER_SEC / data->data_rate[dr];
|
||||
|
||||
*val = period / USEC_PER_SEC;
|
||||
*val2 = period % USEC_PER_SEC;
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ads1015_write_event(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, enum iio_event_info info, int val,
|
||||
int val2)
|
||||
{
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int realbits = chan->scan_type.realbits;
|
||||
int ret = 0;
|
||||
long long period;
|
||||
int i;
|
||||
int dr;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1)) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
data->thresh_data[chan->address].high_thresh = val;
|
||||
else
|
||||
data->thresh_data[chan->address].low_thresh = val;
|
||||
break;
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
dr = data->channel_data[chan->address].data_rate;
|
||||
period = val * USEC_PER_SEC + val2;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ads1015_comp_queue) - 1; i++) {
|
||||
if (period <= ads1015_comp_queue[i] *
|
||||
USEC_PER_SEC / data->data_rate[dr])
|
||||
break;
|
||||
}
|
||||
data->thresh_data[chan->address].comp_queue = i;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ads1015_read_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (data->event_channel == chan->address) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
ret = 1;
|
||||
break;
|
||||
case IIO_EV_DIR_EITHER:
|
||||
ret = (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ads1015_enable_event_config(struct ads1015_data *data,
|
||||
const struct iio_chan_spec *chan, int comp_mode)
|
||||
{
|
||||
int low_thresh = data->thresh_data[chan->address].low_thresh;
|
||||
int high_thresh = data->thresh_data[chan->address].high_thresh;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
if (ads1015_event_channel_enabled(data)) {
|
||||
if (data->event_channel != chan->address ||
|
||||
(data->comp_mode == ADS1015_CFG_COMP_MODE_TRAD &&
|
||||
comp_mode == ADS1015_CFG_COMP_MODE_WINDOW))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (comp_mode == ADS1015_CFG_COMP_MODE_TRAD) {
|
||||
low_thresh = max(-1 << (chan->scan_type.realbits - 1),
|
||||
high_thresh - 1);
|
||||
}
|
||||
ret = regmap_write(data->regmap, ADS1015_LO_THRESH_REG,
|
||||
low_thresh << chan->scan_type.shift);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADS1015_HI_THRESH_REG,
|
||||
high_thresh << chan->scan_type.shift);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ads1015_set_power_state(data, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ads1015_event_channel_enable(data, chan->address, comp_mode);
|
||||
|
||||
ret = ads1015_get_adc_result(data, chan->address, &val);
|
||||
if (ret) {
|
||||
ads1015_event_channel_disable(data, chan->address);
|
||||
ads1015_set_power_state(data, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ads1015_disable_event_config(struct ads1015_data *data,
|
||||
const struct iio_chan_spec *chan, int comp_mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!ads1015_event_channel_enabled(data))
|
||||
return 0;
|
||||
|
||||
if (data->event_channel != chan->address)
|
||||
return 0;
|
||||
|
||||
if (data->comp_mode == ADS1015_CFG_COMP_MODE_TRAD &&
|
||||
comp_mode == ADS1015_CFG_COMP_MODE_WINDOW)
|
||||
return 0;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_COMP_QUE_MASK,
|
||||
ADS1015_CFG_COMP_DISABLE <<
|
||||
ADS1015_CFG_COMP_QUE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ads1015_event_channel_disable(data, chan->address);
|
||||
|
||||
return ads1015_set_power_state(data, false);
|
||||
}
|
||||
|
||||
static int ads1015_write_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
int comp_mode = (dir == IIO_EV_DIR_EITHER) ?
|
||||
ADS1015_CFG_COMP_MODE_WINDOW : ADS1015_CFG_COMP_MODE_TRAD;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
/* Prevent from enabling both buffer and event at a time */
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret) {
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (state)
|
||||
ret = ads1015_enable_event_config(data, chan, comp_mode);
|
||||
else
|
||||
ret = ads1015_disable_event_config(data, chan, comp_mode);
|
||||
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t ads1015_event_handler(int irq, void *priv)
|
||||
{
|
||||
struct iio_dev *indio_dev = priv;
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
/* Clear the latched ALERT/RDY pin */
|
||||
ret = regmap_read(data->regmap, ADS1015_CONV_REG, &val);
|
||||
if (ret)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (ads1015_event_channel_enabled(data)) {
|
||||
enum iio_event_direction dir;
|
||||
u64 code;
|
||||
|
||||
dir = data->comp_mode == ADS1015_CFG_COMP_MODE_TRAD ?
|
||||
IIO_EV_DIR_RISING : IIO_EV_DIR_EITHER;
|
||||
code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, data->event_channel,
|
||||
IIO_EV_TYPE_THRESH, dir);
|
||||
iio_push_event(indio_dev, code, iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ads1015_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
|
||||
/* Prevent from enabling both buffer and event at a time */
|
||||
if (ads1015_event_channel_enabled(data))
|
||||
return -EBUSY;
|
||||
|
||||
return ads1015_set_power_state(iio_priv(indio_dev), true);
|
||||
}
|
||||
|
||||
|
@ -446,7 +790,10 @@ static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
|
|||
.validate_scan_mask = &iio_validate_scan_mask_onehot,
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(scale_available, "3 2 1 0.5 0.25 0.125");
|
||||
static IIO_CONST_ATTR_NAMED(ads1015_scale_available, scale_available,
|
||||
"3 2 1 0.5 0.25 0.125");
|
||||
static IIO_CONST_ATTR_NAMED(ads1115_scale_available, scale_available,
|
||||
"0.1875 0.125 0.0625 0.03125 0.015625 0.007813");
|
||||
|
||||
static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available,
|
||||
sampling_frequency_available, "128 250 490 920 1600 2400 3300");
|
||||
|
@ -454,7 +801,7 @@ static IIO_CONST_ATTR_NAMED(ads1115_sampling_frequency_available,
|
|||
sampling_frequency_available, "8 16 32 64 128 250 475 860");
|
||||
|
||||
static struct attribute *ads1015_attributes[] = {
|
||||
&iio_const_attr_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1015_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
@ -464,7 +811,7 @@ static const struct attribute_group ads1015_attribute_group = {
|
|||
};
|
||||
|
||||
static struct attribute *ads1115_attributes[] = {
|
||||
&iio_const_attr_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1115_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
@ -477,6 +824,10 @@ static const struct iio_info ads1015_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = ads1015_read_raw,
|
||||
.write_raw = ads1015_write_raw,
|
||||
.read_event_value = ads1015_read_event,
|
||||
.write_event_value = ads1015_write_event,
|
||||
.read_event_config = ads1015_read_event_config,
|
||||
.write_event_config = ads1015_write_event_config,
|
||||
.attrs = &ads1015_attribute_group,
|
||||
};
|
||||
|
||||
|
@ -484,6 +835,10 @@ static const struct iio_info ads1115_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = ads1015_read_raw,
|
||||
.write_raw = ads1015_write_raw,
|
||||
.read_event_value = ads1015_read_event,
|
||||
.write_event_value = ads1015_write_event,
|
||||
.read_event_config = ads1015_read_event_config,
|
||||
.write_event_config = ads1015_write_event_config,
|
||||
.attrs = &ads1115_attribute_group,
|
||||
};
|
||||
|
||||
|
@ -573,6 +928,13 @@ static void ads1015_get_channels_config(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
|
||||
{
|
||||
return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MOD_MASK,
|
||||
mode << ADS1015_CFG_MOD_SHIFT);
|
||||
}
|
||||
|
||||
static int ads1015_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -580,6 +942,7 @@ static int ads1015_probe(struct i2c_client *client,
|
|||
struct ads1015_data *data;
|
||||
int ret;
|
||||
enum chip_ids chip;
|
||||
int i;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -614,6 +977,18 @@ static int ads1015_probe(struct i2c_client *client,
|
|||
break;
|
||||
}
|
||||
|
||||
data->event_channel = ADS1015_CHANNELS;
|
||||
/*
|
||||
* Set default lower and upper threshold to min and max value
|
||||
* respectively.
|
||||
*/
|
||||
for (i = 0; i < ADS1015_CHANNELS; i++) {
|
||||
int realbits = indio_dev->channels[i].scan_type.realbits;
|
||||
|
||||
data->thresh_data[i].low_thresh = -1 << (realbits - 1);
|
||||
data->thresh_data[i].high_thresh = (1 << (realbits - 1)) - 1;
|
||||
}
|
||||
|
||||
/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
|
||||
ads1015_get_channels_config(client);
|
||||
|
||||
|
@ -623,16 +998,56 @@ static int ads1015_probe(struct i2c_client *client,
|
|||
return PTR_ERR(data->regmap);
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
ads1015_trigger_handler,
|
||||
&ads1015_buffer_setup_ops);
|
||||
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
|
||||
ads1015_trigger_handler,
|
||||
&ads1015_buffer_setup_ops);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "iio triggered buffer setup failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (client->irq) {
|
||||
unsigned long irq_trig =
|
||||
irqd_get_trigger_type(irq_get_irq_data(client->irq));
|
||||
unsigned int cfg_comp_mask = ADS1015_CFG_COMP_QUE_MASK |
|
||||
ADS1015_CFG_COMP_LAT_MASK | ADS1015_CFG_COMP_POL_MASK;
|
||||
unsigned int cfg_comp =
|
||||
ADS1015_CFG_COMP_DISABLE << ADS1015_CFG_COMP_QUE_SHIFT |
|
||||
1 << ADS1015_CFG_COMP_LAT_SHIFT;
|
||||
|
||||
switch (irq_trig) {
|
||||
case IRQF_TRIGGER_LOW:
|
||||
cfg_comp |= ADS1015_CFG_COMP_POL_LOW;
|
||||
break;
|
||||
case IRQF_TRIGGER_HIGH:
|
||||
cfg_comp |= ADS1015_CFG_COMP_POL_HIGH;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
cfg_comp_mask, cfg_comp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, ads1015_event_handler,
|
||||
irq_trig | IRQF_ONESHOT,
|
||||
client->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ads1015_set_conv_mode(data, ADS1015_CONTINUOUS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->conv_invalid = true;
|
||||
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
if (ret)
|
||||
goto err_buffer_cleanup;
|
||||
return ret;
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, ADS1015_SLEEP_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
pm_runtime_enable(&client->dev);
|
||||
|
@ -640,15 +1055,10 @@ static int ads1015_probe(struct i2c_client *client,
|
|||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failed to register IIO device\n");
|
||||
goto err_buffer_cleanup;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ads1015_remove(struct i2c_client *client)
|
||||
|
@ -662,12 +1072,8 @@ static int ads1015_remove(struct i2c_client *client)
|
|||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
/* power down single shot mode */
|
||||
return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MOD_MASK,
|
||||
ADS1015_SINGLESHOT << ADS1015_CFG_MOD_SHIFT);
|
||||
return ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -676,19 +1082,20 @@ static int ads1015_runtime_suspend(struct device *dev)
|
|||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
|
||||
return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MOD_MASK,
|
||||
ADS1015_SINGLESHOT << ADS1015_CFG_MOD_SHIFT);
|
||||
return ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
|
||||
}
|
||||
|
||||
static int ads1015_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct ads1015_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
|
||||
ADS1015_CFG_MOD_MASK,
|
||||
ADS1015_CONTINUOUS << ADS1015_CFG_MOD_SHIFT);
|
||||
ret = ads1015_set_conv_mode(data, ADS1015_CONTINUOUS);
|
||||
if (!ret)
|
||||
data->conv_invalid = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
@ -37,6 +38,12 @@
|
|||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
/*
|
||||
* In case of ACPI, we use the 5000 mV as default for the reference pin.
|
||||
* Device tree users encode that via the vref-supply regulator.
|
||||
*/
|
||||
#define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000
|
||||
|
||||
#define TI_ADS7950_CR_MANUAL BIT(12)
|
||||
#define TI_ADS7950_CR_WRITE BIT(11)
|
||||
#define TI_ADS7950_CR_CHAN(ch) ((ch) << 7)
|
||||
|
@ -58,6 +65,7 @@ struct ti_ads7950_state {
|
|||
struct spi_message scan_single_msg;
|
||||
|
||||
struct regulator *reg;
|
||||
unsigned int vref_mv;
|
||||
|
||||
unsigned int settings;
|
||||
|
||||
|
@ -305,11 +313,15 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st)
|
|||
{
|
||||
int vref;
|
||||
|
||||
vref = regulator_get_voltage(st->reg);
|
||||
if (vref < 0)
|
||||
return vref;
|
||||
if (st->vref_mv) {
|
||||
vref = st->vref_mv;
|
||||
} else {
|
||||
vref = regulator_get_voltage(st->reg);
|
||||
if (vref < 0)
|
||||
return vref;
|
||||
|
||||
vref /= 1000;
|
||||
vref /= 1000;
|
||||
}
|
||||
|
||||
if (st->settings & TI_ADS7950_CR_RANGE_5V)
|
||||
vref *= 2;
|
||||
|
@ -411,6 +423,10 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
|||
spi_message_init_with_transfers(&st->scan_single_msg,
|
||||
st->scan_single_xfer, 3);
|
||||
|
||||
/* Use hard coded value for reference voltage in ACPI case */
|
||||
if (ACPI_COMPANION(&spi->dev))
|
||||
st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT;
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(st->reg)) {
|
||||
dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
|
||||
|
@ -475,9 +491,27 @@ static const struct spi_device_id ti_ads7950_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
|
||||
|
||||
static const struct of_device_id ads7950_of_table[] = {
|
||||
{ .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info[TI_ADS7950] },
|
||||
{ .compatible = "ti,ads7951", .data = &ti_ads7950_chip_info[TI_ADS7951] },
|
||||
{ .compatible = "ti,ads7952", .data = &ti_ads7950_chip_info[TI_ADS7952] },
|
||||
{ .compatible = "ti,ads7953", .data = &ti_ads7950_chip_info[TI_ADS7953] },
|
||||
{ .compatible = "ti,ads7954", .data = &ti_ads7950_chip_info[TI_ADS7954] },
|
||||
{ .compatible = "ti,ads7955", .data = &ti_ads7950_chip_info[TI_ADS7955] },
|
||||
{ .compatible = "ti,ads7956", .data = &ti_ads7950_chip_info[TI_ADS7956] },
|
||||
{ .compatible = "ti,ads7957", .data = &ti_ads7950_chip_info[TI_ADS7957] },
|
||||
{ .compatible = "ti,ads7958", .data = &ti_ads7950_chip_info[TI_ADS7958] },
|
||||
{ .compatible = "ti,ads7959", .data = &ti_ads7950_chip_info[TI_ADS7959] },
|
||||
{ .compatible = "ti,ads7960", .data = &ti_ads7950_chip_info[TI_ADS7960] },
|
||||
{ .compatible = "ti,ads7961", .data = &ti_ads7950_chip_info[TI_ADS7961] },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads7950_of_table);
|
||||
|
||||
static struct spi_driver ti_ads7950_driver = {
|
||||
.driver = {
|
||||
.name = "ads7950",
|
||||
.of_match_table = ads7950_of_table,
|
||||
},
|
||||
.probe = ti_ads7950_probe,
|
||||
.remove = ti_ads7950_remove,
|
||||
|
|
|
@ -68,7 +68,7 @@ void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
|
|||
xadc_handle_event(indio_dev, i);
|
||||
}
|
||||
|
||||
static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
|
||||
static unsigned int xadc_get_threshold_offset(const struct iio_chan_spec *chan,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
unsigned int offset;
|
||||
|
@ -90,26 +90,24 @@ static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
|
|||
|
||||
static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
|
||||
{
|
||||
if (chan->type == IIO_TEMP) {
|
||||
if (chan->type == IIO_TEMP)
|
||||
return XADC_ALARM_OT_MASK;
|
||||
} else {
|
||||
switch (chan->channel) {
|
||||
case 0:
|
||||
return XADC_ALARM_VCCINT_MASK;
|
||||
case 1:
|
||||
return XADC_ALARM_VCCAUX_MASK;
|
||||
case 2:
|
||||
return XADC_ALARM_VCCBRAM_MASK;
|
||||
case 3:
|
||||
return XADC_ALARM_VCCPINT_MASK;
|
||||
case 4:
|
||||
return XADC_ALARM_VCCPAUX_MASK;
|
||||
case 5:
|
||||
return XADC_ALARM_VCCODDR_MASK;
|
||||
default:
|
||||
/* We will never get here */
|
||||
return 0;
|
||||
}
|
||||
switch (chan->channel) {
|
||||
case 0:
|
||||
return XADC_ALARM_VCCINT_MASK;
|
||||
case 1:
|
||||
return XADC_ALARM_VCCAUX_MASK;
|
||||
case 2:
|
||||
return XADC_ALARM_VCCBRAM_MASK;
|
||||
case 3:
|
||||
return XADC_ALARM_VCCPINT_MASK;
|
||||
case 4:
|
||||
return XADC_ALARM_VCCPAUX_MASK;
|
||||
case 5:
|
||||
return XADC_ALARM_VCCODDR_MASK;
|
||||
default:
|
||||
/* We will never get here */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,13 +71,13 @@ struct xadc {
|
|||
};
|
||||
|
||||
struct xadc_ops {
|
||||
int (*read)(struct xadc *, unsigned int, uint16_t *);
|
||||
int (*write)(struct xadc *, unsigned int, uint16_t);
|
||||
int (*read)(struct xadc *xadc, unsigned int reg, uint16_t *val);
|
||||
int (*write)(struct xadc *xadc, unsigned int reg, uint16_t val);
|
||||
int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev,
|
||||
int irq);
|
||||
void (*update_alarm)(struct xadc *, unsigned int);
|
||||
unsigned long (*get_dclk_rate)(struct xadc *);
|
||||
irqreturn_t (*interrupt_handler)(int, void *);
|
||||
void (*update_alarm)(struct xadc *xadc, unsigned int alarm);
|
||||
unsigned long (*get_dclk_rate)(struct xadc *xadc);
|
||||
irqreturn_t (*interrupt_handler)(int irq, void *devid);
|
||||
|
||||
unsigned int flags;
|
||||
};
|
||||
|
|
|
@ -24,6 +24,8 @@ config ATLAS_PH_SENSOR
|
|||
config CCS811
|
||||
tristate "AMS CCS811 VOC sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here to build I2C interface support for the AMS
|
||||
CCS811 VOC (Volatile Organic Compounds) sensor
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define CCS811_STATUS 0x00
|
||||
|
@ -76,25 +79,42 @@ static const struct iio_chan_spec ccs811_channels[] = {
|
|||
{
|
||||
.type = IIO_CURRENT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE)
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = -1,
|
||||
}, {
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE)
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = -1,
|
||||
}, {
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_CO2,
|
||||
.modified = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE)
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
}, {
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_VOC,
|
||||
.modified = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE)
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -253,6 +273,31 @@ static const struct iio_info ccs811_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t ccs811_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ccs811_data *data = iio_priv(indio_dev);
|
||||
struct i2c_client *client = data->client;
|
||||
s16 buf[8]; /* s16 eCO2 + s16 TVOC + padding + 8 byte timestamp */
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA, 4,
|
||||
(u8 *)&buf);
|
||||
if (ret != 4) {
|
||||
dev_err(&client->dev, "cannot read sensor data\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ccs811_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -305,7 +350,27 @@ static int ccs811_probe(struct i2c_client *client,
|
|||
indio_dev->channels = ccs811_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
ccs811_trigger_handler, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "triggered buffer setup failed\n");
|
||||
goto err_poweroff;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "unable to register iio device\n");
|
||||
goto err_buffer_cleanup;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_poweroff:
|
||||
i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE, CCS811_MODE_IDLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ccs811_remove(struct i2c_client *client)
|
||||
|
@ -313,6 +378,7 @@ static int ccs811_remove(struct i2c_client *client)
|
|||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
|
||||
CCS811_MODE_IDLE);
|
||||
|
|
|
@ -125,7 +125,7 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
|||
goto err_vref;
|
||||
}
|
||||
|
||||
priv->rst = devm_reset_control_get(dev, NULL);
|
||||
priv->rst = devm_reset_control_get_exclusive(dev, NULL);
|
||||
if (!IS_ERR(priv->rst)) {
|
||||
reset_control_assert(priv->rst);
|
||||
udelay(2);
|
||||
|
|
|
@ -505,7 +505,7 @@ static SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume);
|
|||
#define APDS9300_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct i2c_device_id apds9300_id[] = {
|
||||
static const struct i2c_device_id apds9300_id[] = {
|
||||
{ APDS9300_DRV_NAME, 0 },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -924,7 +924,7 @@ static const struct dev_pm_ops tsl2583_pm_ops = {
|
|||
SET_RUNTIME_PM_OPS(tsl2583_suspend, tsl2583_resume, NULL)
|
||||
};
|
||||
|
||||
static struct i2c_device_id tsl2583_idtable[] = {
|
||||
static const struct i2c_device_id tsl2583_idtable[] = {
|
||||
{ "tsl2580", 0 },
|
||||
{ "tsl2581", 1 },
|
||||
{ "tsl2583", 2 },
|
||||
|
|
|
@ -13,8 +13,8 @@ config AK8974
|
|||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Asahi Kasei AK8974 or
|
||||
AMI305 I2C-based 3-axis magnetometer chips.
|
||||
Say yes here to build support for Asahi Kasei AK8974, AMI305 or
|
||||
AMI306 I2C-based 3-axis magnetometer chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ak8974.
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
@ -36,7 +37,7 @@
|
|||
* and MSB is at the next higher address.
|
||||
*/
|
||||
|
||||
/* These registers are common for AK8974 and AMI305 */
|
||||
/* These registers are common for AK8974 and AMI30x */
|
||||
#define AK8974_SELFTEST 0x0C
|
||||
#define AK8974_SELFTEST_IDLE 0x55
|
||||
#define AK8974_SELFTEST_OK 0xAA
|
||||
|
@ -44,6 +45,7 @@
|
|||
#define AK8974_INFO 0x0D
|
||||
|
||||
#define AK8974_WHOAMI 0x0F
|
||||
#define AK8974_WHOAMI_VALUE_AMI306 0x46
|
||||
#define AK8974_WHOAMI_VALUE_AMI305 0x47
|
||||
#define AK8974_WHOAMI_VALUE_AK8974 0x48
|
||||
|
||||
|
@ -73,6 +75,35 @@
|
|||
#define AK8974_TEMP 0x31
|
||||
#define AMI305_TEMP 0x60
|
||||
|
||||
/* AMI306-specific control register */
|
||||
#define AMI306_CTRL4 0x5C
|
||||
|
||||
/* AMI306 factory calibration data */
|
||||
|
||||
/* fine axis sensitivity */
|
||||
#define AMI306_FINEOUTPUT_X 0x90
|
||||
#define AMI306_FINEOUTPUT_Y 0x92
|
||||
#define AMI306_FINEOUTPUT_Z 0x94
|
||||
|
||||
/* axis sensitivity */
|
||||
#define AMI306_SENS_X 0x96
|
||||
#define AMI306_SENS_Y 0x98
|
||||
#define AMI306_SENS_Z 0x9A
|
||||
|
||||
/* axis cross-interference */
|
||||
#define AMI306_GAIN_PARA_XZ 0x9C
|
||||
#define AMI306_GAIN_PARA_XY 0x9D
|
||||
#define AMI306_GAIN_PARA_YZ 0x9E
|
||||
#define AMI306_GAIN_PARA_YX 0x9F
|
||||
#define AMI306_GAIN_PARA_ZY 0xA0
|
||||
#define AMI306_GAIN_PARA_ZX 0xA1
|
||||
|
||||
/* offset at ZERO magnetic field */
|
||||
#define AMI306_OFFZERO_X 0xF8
|
||||
#define AMI306_OFFZERO_Y 0xFA
|
||||
#define AMI306_OFFZERO_Z 0xFC
|
||||
|
||||
|
||||
#define AK8974_INT_X_HIGH BIT(7) /* Axis over +threshold */
|
||||
#define AK8974_INT_Y_HIGH BIT(6)
|
||||
#define AK8974_INT_Z_HIGH BIT(5)
|
||||
|
@ -158,6 +189,26 @@ struct ak8974 {
|
|||
static const char ak8974_reg_avdd[] = "avdd";
|
||||
static const char ak8974_reg_dvdd[] = "dvdd";
|
||||
|
||||
static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val)
|
||||
{
|
||||
int ret;
|
||||
__le16 bulk;
|
||||
|
||||
ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = le16_to_cpu(bulk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak8974_set_u16_val(struct ak8974 *ak8974, u8 reg, u16 val)
|
||||
{
|
||||
__le16 bulk = cpu_to_le16(val);
|
||||
|
||||
return regmap_bulk_write(ak8974->map, reg, &bulk, 2);
|
||||
}
|
||||
|
||||
static int ak8974_set_power(struct ak8974 *ak8974, bool mode)
|
||||
{
|
||||
int ret;
|
||||
|
@ -209,6 +260,12 @@ static int ak8974_configure(struct ak8974 *ak8974)
|
|||
ret = regmap_write(ak8974->map, AK8974_CTRL3, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI306) {
|
||||
/* magic from datasheet: set high-speed measurement mode */
|
||||
ret = ak8974_set_u16_val(ak8974, AMI306_CTRL4, 0xA07E);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -388,17 +445,18 @@ static int ak8974_selftest(struct ak8974 *ak8974)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val)
|
||||
static void ak8974_read_calib_data(struct ak8974 *ak8974, unsigned int reg,
|
||||
__le16 *tab, size_t tab_size)
|
||||
{
|
||||
int ret;
|
||||
__le16 bulk;
|
||||
|
||||
ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = le16_to_cpu(bulk);
|
||||
|
||||
return 0;
|
||||
int ret = regmap_bulk_read(ak8974->map, reg, tab, tab_size);
|
||||
if (ret) {
|
||||
memset(tab, 0xFF, tab_size);
|
||||
dev_warn(&ak8974->i2c->dev,
|
||||
"can't read calibration data (regs %u..%zu): %d\n",
|
||||
reg, reg + tab_size - 1, ret);
|
||||
} else {
|
||||
add_device_randomness(tab, tab_size);
|
||||
}
|
||||
}
|
||||
|
||||
static int ak8974_detect(struct ak8974 *ak8974)
|
||||
|
@ -413,9 +471,13 @@ static int ak8974_detect(struct ak8974 *ak8974)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = "ami305";
|
||||
|
||||
switch (whoami) {
|
||||
case AK8974_WHOAMI_VALUE_AMI306:
|
||||
name = "ami306";
|
||||
/* fall-through */
|
||||
case AK8974_WHOAMI_VALUE_AMI305:
|
||||
name = "ami305";
|
||||
ret = regmap_read(ak8974->map, AMI305_VER, &fw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -423,6 +485,7 @@ static int ak8974_detect(struct ak8974 *ak8974)
|
|||
ret = ak8974_get_u16_val(ak8974, AMI305_SN, &sn);
|
||||
if (ret)
|
||||
return ret;
|
||||
add_device_randomness(&sn, sizeof(sn));
|
||||
dev_info(&ak8974->i2c->dev,
|
||||
"detected %s, FW ver %02x, S/N: %04x\n",
|
||||
name, fw, sn);
|
||||
|
@ -440,6 +503,33 @@ static int ak8974_detect(struct ak8974 *ak8974)
|
|||
ak8974->name = name;
|
||||
ak8974->variant = whoami;
|
||||
|
||||
if (whoami == AK8974_WHOAMI_VALUE_AMI306) {
|
||||
__le16 fab_data1[9], fab_data2[3];
|
||||
int i;
|
||||
|
||||
ak8974_read_calib_data(ak8974, AMI306_FINEOUTPUT_X,
|
||||
fab_data1, sizeof(fab_data1));
|
||||
ak8974_read_calib_data(ak8974, AMI306_OFFZERO_X,
|
||||
fab_data2, sizeof(fab_data2));
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
static const char axis[3] = "XYZ";
|
||||
static const char pgaxis[6] = "ZYZXYX";
|
||||
unsigned offz = le16_to_cpu(fab_data2[i]) & 0x7F;
|
||||
unsigned fine = le16_to_cpu(fab_data1[i]);
|
||||
unsigned sens = le16_to_cpu(fab_data1[i + 3]);
|
||||
unsigned pgain1 = le16_to_cpu(fab_data1[i + 6]);
|
||||
unsigned pgain2 = pgain1 >> 8;
|
||||
|
||||
pgain1 &= 0xFF;
|
||||
|
||||
dev_info(&ak8974->i2c->dev,
|
||||
"factory calibration for axis %c: offz=%u sens=%u fine=%u pga%c=%u pga%c=%u\n",
|
||||
axis[i], offz, sens, fine, pgaxis[i * 2],
|
||||
pgain1, pgaxis[i * 2 + 1], pgain2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -602,19 +692,27 @@ static bool ak8974_writeable_reg(struct device *dev, unsigned int reg)
|
|||
case AMI305_OFFSET_Y + 1:
|
||||
case AMI305_OFFSET_Z:
|
||||
case AMI305_OFFSET_Z + 1:
|
||||
if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI305)
|
||||
return true;
|
||||
return false;
|
||||
return ak8974->variant == AK8974_WHOAMI_VALUE_AMI305 ||
|
||||
ak8974->variant == AK8974_WHOAMI_VALUE_AMI306;
|
||||
case AMI306_CTRL4:
|
||||
case AMI306_CTRL4 + 1:
|
||||
return ak8974->variant == AK8974_WHOAMI_VALUE_AMI306;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ak8974_precious_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg == AK8974_INT_CLEAR;
|
||||
}
|
||||
|
||||
static const struct regmap_config ak8974_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xff,
|
||||
.writeable_reg = ak8974_writeable_reg,
|
||||
.precious_reg = ak8974_precious_reg,
|
||||
};
|
||||
|
||||
static int ak8974_probe(struct i2c_client *i2c,
|
||||
|
@ -678,7 +776,7 @@ static int ak8974_probe(struct i2c_client *i2c,
|
|||
|
||||
ret = ak8974_detect(ak8974);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "neither AK8974 nor AMI305 found\n");
|
||||
dev_err(&i2c->dev, "neither AK8974 nor AMI30x found\n");
|
||||
goto power_off;
|
||||
}
|
||||
|
||||
|
@ -827,6 +925,7 @@ static const struct dev_pm_ops ak8974_dev_pm_ops = {
|
|||
|
||||
static const struct i2c_device_id ak8974_id[] = {
|
||||
{"ami305", 0 },
|
||||
{"ami306", 0 },
|
||||
{"ak8974", 0 },
|
||||
{}
|
||||
};
|
||||
|
@ -850,7 +949,7 @@ static struct i2c_driver ak8974_driver = {
|
|||
};
|
||||
module_i2c_driver(ak8974_driver);
|
||||
|
||||
MODULE_DESCRIPTION("AK8974 and AMI305 3-axis magnetometer driver");
|
||||
MODULE_DESCRIPTION("AK8974 and AMI30x 3-axis magnetometer driver");
|
||||
MODULE_AUTHOR("Samu Onkalo");
|
||||
MODULE_AUTHOR("Linus Walleij");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
|
||||
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
|
||||
#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn"
|
||||
#define LIS2MDL_MAGN_DEV_NAME "lis2mdl"
|
||||
|
||||
int st_magn_common_probe(struct iio_dev *indio_dev);
|
||||
void st_magn_common_remove(struct iio_dev *indio_dev);
|
||||
|
|
|
@ -323,6 +323,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
|
|||
.wai_addr = 0x4f,
|
||||
.sensors_supported = {
|
||||
[0] = LSM303AGR_MAGN_DEV_NAME,
|
||||
[1] = LIS2MDL_MAGN_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_magn_3_16bit_channels,
|
||||
.odr = {
|
||||
|
|
|
@ -40,6 +40,10 @@ static const struct of_device_id st_magn_of_match[] = {
|
|||
.compatible = "st,lsm303agr-magn",
|
||||
.data = LSM303AGR_MAGN_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lis2mdl",
|
||||
.data = LIS2MDL_MAGN_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_magn_of_match);
|
||||
|
@ -85,6 +89,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
|
|||
{ LSM303DLM_MAGN_DEV_NAME },
|
||||
{ LIS3MDL_MAGN_DEV_NAME },
|
||||
{ LSM303AGR_MAGN_DEV_NAME },
|
||||
{ LIS2MDL_MAGN_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
|
||||
|
|
|
@ -33,6 +33,10 @@ static const struct of_device_id st_magn_of_match[] = {
|
|||
.compatible = "st,lsm303agr-magn",
|
||||
.data = LSM303AGR_MAGN_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lis2mdl",
|
||||
.data = LIS2MDL_MAGN_DEV_NAME,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_magn_of_match);
|
||||
|
@ -74,6 +78,7 @@ static int st_magn_spi_remove(struct spi_device *spi)
|
|||
static const struct spi_device_id st_magn_id_table[] = {
|
||||
{ LIS3MDL_MAGN_DEV_NAME },
|
||||
{ LSM303AGR_MAGN_DEV_NAME },
|
||||
{ LIS2MDL_MAGN_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
|
||||
|
|
|
@ -390,7 +390,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
|
|||
.drdy_irq = {
|
||||
.addr = 0x23,
|
||||
.mask_int1 = 0x01,
|
||||
.mask_int2 = 0x10,
|
||||
.mask_int2 = 0x00,
|
||||
.addr_ihl = 0x22,
|
||||
.mask_ihl = 0x80,
|
||||
.addr_od = 0x22,
|
||||
|
@ -449,7 +449,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
|
|||
.drdy_irq = {
|
||||
.addr = 0x12,
|
||||
.mask_int1 = 0x04,
|
||||
.mask_int2 = 0x08,
|
||||
.mask_int2 = 0x00,
|
||||
.addr_ihl = 0x12,
|
||||
.mask_ihl = 0x80,
|
||||
.addr_od = 0x12,
|
||||
|
|
|
@ -57,12 +57,12 @@ config SX9500
|
|||
module will be called sx9500.
|
||||
|
||||
config SRF08
|
||||
tristate "Devantech SRF08 ultrasonic ranger sensor"
|
||||
tristate "Devantech SRF02/SRF08/SRF10 ultrasonic ranger sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to build a driver for Devantech SRF08 ultrasonic
|
||||
ranger sensor. This driver can be used to measure the distance
|
||||
of objects.
|
||||
Say Y here to build a driver for Devantech SRF02/SRF08/SRF10
|
||||
ultrasonic ranger sensors with i2c interface.
|
||||
This driver can be used to measure the distance of objects.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called srf08.
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
/*
|
||||
* srf08.c - Support for Devantech SRF08 ultrasonic ranger
|
||||
* srf08.c - Support for Devantech SRFxx ultrasonic ranger
|
||||
* with i2c interface
|
||||
* actually supported are srf02, srf08, srf10
|
||||
*
|
||||
* Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
|
||||
* Copyright (c) 2016, 2017 Andreas Klinger <ak@it-klinger.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* For details about the device see:
|
||||
* http://www.robot-electronics.co.uk/htm/srf08tech.html
|
||||
* http://www.robot-electronics.co.uk/htm/srf10tech.htm
|
||||
* http://www.robot-electronics.co.uk/htm/srf02tech.htm
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
|
@ -18,6 +22,9 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
/* registers of SRF08 device */
|
||||
#define SRF08_WRITE_COMMAND 0x00 /* Command Register */
|
||||
|
@ -30,14 +37,46 @@
|
|||
|
||||
#define SRF08_CMD_RANGING_CM 0x51 /* Ranging Mode - Result in cm */
|
||||
|
||||
#define SRF08_DEFAULT_GAIN 1025 /* default analogue value of Gain */
|
||||
#define SRF08_DEFAULT_RANGE 6020 /* default value of Range in mm */
|
||||
enum srf08_sensor_type {
|
||||
SRF02,
|
||||
SRF08,
|
||||
SRF10,
|
||||
SRF_MAX_TYPE
|
||||
};
|
||||
|
||||
struct srf08_chip_info {
|
||||
const int *sensitivity_avail;
|
||||
int num_sensitivity_avail;
|
||||
int sensitivity_default;
|
||||
|
||||
/* default value of Range in mm */
|
||||
int range_default;
|
||||
};
|
||||
|
||||
struct srf08_data {
|
||||
struct i2c_client *client;
|
||||
int sensitivity; /* Gain */
|
||||
int range_mm; /* max. Range in mm */
|
||||
|
||||
/*
|
||||
* Gain in the datasheet is called sensitivity here to distinct it
|
||||
* from the gain used with amplifiers of adc's
|
||||
*/
|
||||
int sensitivity;
|
||||
|
||||
/* max. Range in mm */
|
||||
int range_mm;
|
||||
struct mutex lock;
|
||||
|
||||
/*
|
||||
* triggered buffer
|
||||
* 1x16-bit channel + 3x16 padding + 4x16 timestamp
|
||||
*/
|
||||
s16 buffer[8];
|
||||
|
||||
/* Sensor-Type */
|
||||
enum srf08_sensor_type sensor_type;
|
||||
|
||||
/* Chip-specific information */
|
||||
const struct srf08_chip_info *chip_info;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -47,11 +86,42 @@ struct srf08_data {
|
|||
* But with ADC's this term is already used differently and that's why it
|
||||
* is called "Sensitivity" here.
|
||||
*/
|
||||
static const int srf08_sensitivity[] = {
|
||||
static const struct srf08_chip_info srf02_chip_info = {
|
||||
.sensitivity_avail = NULL,
|
||||
.num_sensitivity_avail = 0,
|
||||
.sensitivity_default = 0,
|
||||
|
||||
.range_default = 0,
|
||||
};
|
||||
|
||||
static const int srf08_sensitivity_avail[] = {
|
||||
94, 97, 100, 103, 107, 110, 114, 118,
|
||||
123, 128, 133, 139, 145, 152, 159, 168,
|
||||
177, 187, 199, 212, 227, 245, 265, 288,
|
||||
317, 352, 395, 450, 524, 626, 777, 1025 };
|
||||
317, 352, 395, 450, 524, 626, 777, 1025
|
||||
};
|
||||
|
||||
static const struct srf08_chip_info srf08_chip_info = {
|
||||
.sensitivity_avail = srf08_sensitivity_avail,
|
||||
.num_sensitivity_avail = ARRAY_SIZE(srf08_sensitivity_avail),
|
||||
.sensitivity_default = 1025,
|
||||
|
||||
.range_default = 6020,
|
||||
};
|
||||
|
||||
static const int srf10_sensitivity_avail[] = {
|
||||
40, 40, 50, 60, 70, 80, 100, 120,
|
||||
140, 200, 250, 300, 350, 400, 500, 600,
|
||||
700,
|
||||
};
|
||||
|
||||
static const struct srf08_chip_info srf10_chip_info = {
|
||||
.sensitivity_avail = srf10_sensitivity_avail,
|
||||
.num_sensitivity_avail = ARRAY_SIZE(srf10_sensitivity_avail),
|
||||
.sensitivity_default = 700,
|
||||
|
||||
.range_default = 6020,
|
||||
};
|
||||
|
||||
static int srf08_read_ranging(struct srf08_data *data)
|
||||
{
|
||||
|
@ -110,6 +180,29 @@ static int srf08_read_ranging(struct srf08_data *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t srf08_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct srf08_data *data = iio_priv(indio_dev);
|
||||
s16 sensor_data;
|
||||
|
||||
sensor_data = srf08_read_ranging(data);
|
||||
if (sensor_data < 0)
|
||||
goto err;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
data->buffer[0] = sensor_data;
|
||||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
data->buffer, pf->timestamp);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int srf08_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *channel, int *val,
|
||||
int *val2, long mask)
|
||||
|
@ -225,9 +318,13 @@ static ssize_t srf08_show_sensitivity_available(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int i, len = 0;
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct srf08_data *data = iio_priv(indio_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
|
||||
len += sprintf(buf + len, "%d ", srf08_sensitivity[i]);
|
||||
for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
|
||||
if (data->chip_info->sensitivity_avail[i])
|
||||
len += sprintf(buf + len, "%d ",
|
||||
data->chip_info->sensitivity_avail[i]);
|
||||
|
||||
len += sprintf(buf + len, "\n");
|
||||
|
||||
|
@ -256,19 +353,21 @@ static ssize_t srf08_write_sensitivity(struct srf08_data *data,
|
|||
int ret, i;
|
||||
u8 regval;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
|
||||
if (val == srf08_sensitivity[i]) {
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
|
||||
if (val && (val == data->chip_info->sensitivity_avail[i])) {
|
||||
regval = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(srf08_sensitivity))
|
||||
if (i >= data->chip_info->num_sensitivity_avail)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
SRF08_WRITE_MAX_GAIN, regval);
|
||||
ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_MAX_GAIN, regval);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "write_sensitivity - err: %d\n", ret);
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -323,7 +422,15 @@ static const struct iio_chan_spec srf08_channels[] = {
|
|||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
};
|
||||
|
||||
static const struct iio_info srf08_info = {
|
||||
|
@ -332,6 +439,15 @@ static const struct iio_info srf08_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
* srf02 don't have an adjustable range or sensitivity,
|
||||
* so we don't need attributes at all
|
||||
*/
|
||||
static const struct iio_info srf02_info = {
|
||||
.read_raw = srf08_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int srf08_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -352,34 +468,84 @@ static int srf08_probe(struct i2c_client *client,
|
|||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->sensor_type = (enum srf08_sensor_type)id->driver_data;
|
||||
|
||||
indio_dev->name = "srf08";
|
||||
switch (data->sensor_type) {
|
||||
case SRF02:
|
||||
data->chip_info = &srf02_chip_info;
|
||||
indio_dev->info = &srf02_info;
|
||||
break;
|
||||
case SRF08:
|
||||
data->chip_info = &srf08_chip_info;
|
||||
indio_dev->info = &srf08_info;
|
||||
break;
|
||||
case SRF10:
|
||||
data->chip_info = &srf10_chip_info;
|
||||
indio_dev->info = &srf08_info;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &srf08_info;
|
||||
indio_dev->channels = srf08_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
/*
|
||||
* set default values of device here
|
||||
* these register values cannot be read from the hardware
|
||||
* therefore set driver specific default values
|
||||
*/
|
||||
ret = srf08_write_range_mm(data, SRF08_DEFAULT_RANGE);
|
||||
if (ret < 0)
|
||||
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
|
||||
iio_pollfunc_store_time, srf08_trigger_handler, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "setup of iio triggered buffer failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = srf08_write_sensitivity(data, SRF08_DEFAULT_GAIN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (data->chip_info->range_default) {
|
||||
/*
|
||||
* set default range of device in mm here
|
||||
* these register values cannot be read from the hardware
|
||||
* therefore set driver specific default values
|
||||
*
|
||||
* srf02 don't have a default value so it'll be omitted
|
||||
*/
|
||||
ret = srf08_write_range_mm(data,
|
||||
data->chip_info->range_default);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data->chip_info->sensitivity_default) {
|
||||
/*
|
||||
* set default sensitivity of device here
|
||||
* these register values cannot be read from the hardware
|
||||
* therefore set driver specific default values
|
||||
*
|
||||
* srf02 don't have a default value so it'll be omitted
|
||||
*/
|
||||
ret = srf08_write_sensitivity(data,
|
||||
data->chip_info->sensitivity_default);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id of_srf08_match[] = {
|
||||
{ .compatible = "devantech,srf02", (void *)SRF02},
|
||||
{ .compatible = "devantech,srf08", (void *)SRF08},
|
||||
{ .compatible = "devantech,srf10", (void *)SRF10},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, of_srf08_match);
|
||||
|
||||
static const struct i2c_device_id srf08_id[] = {
|
||||
{ "srf08", 0 },
|
||||
{ "srf02", SRF02 },
|
||||
{ "srf08", SRF08 },
|
||||
{ "srf10", SRF10 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, srf08_id);
|
||||
|
@ -387,6 +553,7 @@ MODULE_DEVICE_TABLE(i2c, srf08_id);
|
|||
static struct i2c_driver srf08_driver = {
|
||||
.driver = {
|
||||
.name = "srf08",
|
||||
.of_match_table = of_srf08_match,
|
||||
},
|
||||
.probe = srf08_probe,
|
||||
.id_table = srf08_id,
|
||||
|
@ -394,5 +561,5 @@ static struct i2c_driver srf08_driver = {
|
|||
module_i2c_driver(srf08_driver);
|
||||
|
||||
MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
|
||||
MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver");
|
||||
MODULE_DESCRIPTION("Devantech SRF02/SRF08/SRF10 i2c ultrasonic ranger driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/mfd/stm32-timers.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define MAX_TRIGGERS 7
|
||||
#define MAX_VALIDS 5
|
||||
|
@ -28,9 +29,14 @@ static const void *triggers_table[][MAX_TRIGGERS] = {
|
|||
{ TIM7_TRGO,},
|
||||
{ TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},
|
||||
{ TIM9_TRGO, TIM9_CH1, TIM9_CH2,},
|
||||
{ }, /* timer 10 */
|
||||
{ }, /* timer 11 */
|
||||
{ TIM10_OC1,},
|
||||
{ TIM11_OC1,},
|
||||
{ TIM12_TRGO, TIM12_CH1, TIM12_CH2,},
|
||||
{ TIM13_OC1,},
|
||||
{ TIM14_OC1,},
|
||||
{ TIM15_TRGO,},
|
||||
{ TIM16_OC1,},
|
||||
{ TIM17_OC1,},
|
||||
};
|
||||
|
||||
/* List the triggers accepted by each timer */
|
||||
|
@ -43,10 +49,30 @@ static const void *valids_table[][MAX_VALIDS] = {
|
|||
{ }, /* timer 6 */
|
||||
{ }, /* timer 7 */
|
||||
{ TIM1_TRGO, TIM2_TRGO, TIM4_TRGO, TIM5_TRGO,},
|
||||
{ TIM2_TRGO, TIM3_TRGO,},
|
||||
{ TIM2_TRGO, TIM3_TRGO, TIM10_OC1, TIM11_OC1,},
|
||||
{ }, /* timer 10 */
|
||||
{ }, /* timer 11 */
|
||||
{ TIM4_TRGO, TIM5_TRGO,},
|
||||
{ TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,},
|
||||
};
|
||||
|
||||
static const void *stm32h7_valids_table[][MAX_VALIDS] = {
|
||||
{ TIM15_TRGO, TIM2_TRGO, TIM3_TRGO, TIM4_TRGO,},
|
||||
{ TIM1_TRGO, TIM8_TRGO, TIM3_TRGO, TIM4_TRGO,},
|
||||
{ TIM1_TRGO, TIM2_TRGO, TIM15_TRGO, TIM4_TRGO,},
|
||||
{ TIM1_TRGO, TIM2_TRGO, TIM3_TRGO, TIM8_TRGO,},
|
||||
{ TIM1_TRGO, TIM8_TRGO, TIM3_TRGO, TIM4_TRGO,},
|
||||
{ }, /* timer 6 */
|
||||
{ }, /* timer 7 */
|
||||
{ TIM1_TRGO, TIM2_TRGO, TIM4_TRGO, TIM5_TRGO,},
|
||||
{ }, /* timer 9 */
|
||||
{ }, /* timer 10 */
|
||||
{ }, /* timer 11 */
|
||||
{ TIM4_TRGO, TIM5_TRGO, TIM13_OC1, TIM14_OC1,},
|
||||
{ }, /* timer 13 */
|
||||
{ }, /* timer 14 */
|
||||
{ TIM1_TRGO, TIM3_TRGO, TIM16_OC1, TIM17_OC1,},
|
||||
{ }, /* timer 16 */
|
||||
{ }, /* timer 17 */
|
||||
};
|
||||
|
||||
struct stm32_timer_trigger {
|
||||
|
@ -59,11 +85,21 @@ struct stm32_timer_trigger {
|
|||
bool has_trgo2;
|
||||
};
|
||||
|
||||
struct stm32_timer_trigger_cfg {
|
||||
const void *(*valids_table)[MAX_VALIDS];
|
||||
const unsigned int num_valids_table;
|
||||
};
|
||||
|
||||
static bool stm32_timer_is_trgo2_name(const char *name)
|
||||
{
|
||||
return !!strstr(name, "trgo2");
|
||||
}
|
||||
|
||||
static bool stm32_timer_is_trgo_name(const char *name)
|
||||
{
|
||||
return (!!strstr(name, "trgo") && !strstr(name, "trgo2"));
|
||||
}
|
||||
|
||||
static int stm32_timer_start(struct stm32_timer_trigger *priv,
|
||||
struct iio_trigger *trig,
|
||||
unsigned int frequency)
|
||||
|
@ -328,6 +364,7 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
|
|||
|
||||
while (cur && *cur) {
|
||||
struct iio_trigger *trig;
|
||||
bool cur_is_trgo = stm32_timer_is_trgo_name(*cur);
|
||||
bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur);
|
||||
|
||||
if (cur_is_trgo2 && !priv->has_trgo2) {
|
||||
|
@ -344,10 +381,9 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
|
|||
|
||||
/*
|
||||
* sampling frequency and master mode attributes
|
||||
* should only be available on trgo trigger which
|
||||
* is always the first in the list.
|
||||
* should only be available on trgo/trgo2 triggers
|
||||
*/
|
||||
if (cur == priv->triggers || cur_is_trgo2)
|
||||
if (cur_is_trgo || cur_is_trgo2)
|
||||
trig->dev.groups = stm32_trigger_attr_groups;
|
||||
|
||||
iio_trigger_set_drvdata(trig, priv);
|
||||
|
@ -734,18 +770,22 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct stm32_timer_trigger *priv;
|
||||
struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
|
||||
const struct stm32_timer_trigger_cfg *cfg;
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "reg", &index))
|
||||
return -EINVAL;
|
||||
|
||||
cfg = (const struct stm32_timer_trigger_cfg *)
|
||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
||||
|
||||
if (index >= ARRAY_SIZE(triggers_table) ||
|
||||
index >= ARRAY_SIZE(valids_table))
|
||||
index >= cfg->num_valids_table)
|
||||
return -EINVAL;
|
||||
|
||||
/* Create an IIO device only if we have triggers to be validated */
|
||||
if (*valids_table[index])
|
||||
if (*cfg->valids_table[index])
|
||||
priv = stm32_setup_counter_device(dev);
|
||||
else
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
|
@ -758,7 +798,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
|
|||
priv->clk = ddata->clk;
|
||||
priv->max_arr = ddata->max_arr;
|
||||
priv->triggers = triggers_table[index];
|
||||
priv->valids = valids_table[index];
|
||||
priv->valids = cfg->valids_table[index];
|
||||
stm32_timer_detect_trgo2(priv);
|
||||
|
||||
ret = stm32_setup_iio_triggers(priv);
|
||||
|
@ -770,8 +810,24 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
|
||||
.valids_table = valids_table,
|
||||
.num_valids_table = ARRAY_SIZE(valids_table),
|
||||
};
|
||||
|
||||
static const struct stm32_timer_trigger_cfg stm32h7_timer_trg_cfg = {
|
||||
.valids_table = stm32h7_valids_table,
|
||||
.num_valids_table = ARRAY_SIZE(stm32h7_valids_table),
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_trig_of_match[] = {
|
||||
{ .compatible = "st,stm32-timer-trigger", },
|
||||
{
|
||||
.compatible = "st,stm32-timer-trigger",
|
||||
.data = (void *)&stm32_timer_trg_cfg,
|
||||
}, {
|
||||
.compatible = "st,stm32h7-timer-trigger",
|
||||
.data = (void *)&stm32h7_timer_trg_cfg,
|
||||
},
|
||||
{ /* end node */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
|
||||
|
|
|
@ -57,8 +57,8 @@ static int ad7606_par_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq\n");
|
||||
return -ENODEV;
|
||||
dev_err(&pdev->dev, "no irq: %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
|
|
@ -55,10 +55,24 @@
|
|||
#define TIM9_CH1 "tim9_ch1"
|
||||
#define TIM9_CH2 "tim9_ch2"
|
||||
|
||||
#define TIM10_OC1 "tim10_oc1"
|
||||
|
||||
#define TIM11_OC1 "tim11_oc1"
|
||||
|
||||
#define TIM12_TRGO "tim12_trgo"
|
||||
#define TIM12_CH1 "tim12_ch1"
|
||||
#define TIM12_CH2 "tim12_ch2"
|
||||
|
||||
#define TIM13_OC1 "tim13_oc1"
|
||||
|
||||
#define TIM14_OC1 "tim14_oc1"
|
||||
|
||||
#define TIM15_TRGO "tim15_trgo"
|
||||
|
||||
#define TIM16_OC1 "tim16_oc1"
|
||||
|
||||
#define TIM17_OC1 "tim17_oc1"
|
||||
|
||||
bool is_stm32_timer_trigger(struct iio_trigger *trig);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -93,7 +93,7 @@ kvm_stat: FORCE
|
|||
all: acpi cgroup cpupower gpio hv firewire lguest liblockdep \
|
||||
perf selftests turbostat usb \
|
||||
virtio vm net x86_energy_perf_policy \
|
||||
tmon freefall objtool kvm_stat
|
||||
tmon freefall iio objtool kvm_stat
|
||||
|
||||
acpi_install:
|
||||
$(call descend,power/$(@:_install=),install)
|
||||
|
@ -101,7 +101,7 @@ acpi_install:
|
|||
cpupower_install:
|
||||
$(call descend,power/$(@:_install=),install)
|
||||
|
||||
cgroup_install firewire_install gpio_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install:
|
||||
cgroup_install firewire_install gpio_install hv_install iio_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install:
|
||||
$(call descend,$(@:_install=),install)
|
||||
|
||||
liblockdep_install:
|
||||
|
@ -123,7 +123,7 @@ kvm_stat_install:
|
|||
$(call descend,kvm/$(@:_install=),install)
|
||||
|
||||
install: acpi_install cgroup_install cpupower_install gpio_install \
|
||||
hv_install firewire_install lguest_install liblockdep_install \
|
||||
hv_install firewire_install iio_install lguest_install liblockdep_install \
|
||||
perf_install selftests_install turbostat_install usb_install \
|
||||
virtio_install vm_install net_install x86_energy_perf_policy_install \
|
||||
tmon_install freefall_install objtool_install kvm_stat_install
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
lsiio-y += lsiio.o iio_utils.o
|
||||
iio_event_monitor-y += iio_event_monitor.o iio_utils.o
|
||||
iio_generic_buffer-y += iio_generic_buffer.o iio_utils.o
|
|
@ -1,31 +1,67 @@
|
|||
include ../scripts/Makefile.include
|
||||
|
||||
bindir ?= /usr/bin
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
endif
|
||||
|
||||
# Do not use make's built-in rules
|
||||
# (this improves performance and avoids hard-to-debug behaviour);
|
||||
MAKEFLAGS += -r
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CFLAGS += -Wall -g -D_GNU_SOURCE -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
|
||||
LD = $(CROSS_COMPILE)ld
|
||||
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
|
||||
|
||||
BINDIR=usr/bin
|
||||
INSTALL_PROGRAM=install -m 755 -p
|
||||
DEL_FILE=rm -f
|
||||
ALL_TARGETS := iio_event_monitor lsiio iio_generic_buffer
|
||||
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
|
||||
|
||||
all: iio_event_monitor lsiio iio_generic_buffer
|
||||
all: $(ALL_PROGRAMS)
|
||||
|
||||
iio_event_monitor: iio_event_monitor.o iio_utils.o
|
||||
export srctree OUTPUT CC LD CFLAGS
|
||||
include $(srctree)/tools/build/Makefile.include
|
||||
|
||||
lsiio: lsiio.o iio_utils.o
|
||||
#
|
||||
# We need the following to be outside of kernel tree
|
||||
#
|
||||
$(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio
|
||||
mkdir -p $(OUTPUT)include/linux/iio 2>&1 || true
|
||||
ln -sf $(CURDIR)/../../include/uapi/linux/iio/events.h $@
|
||||
ln -sf $(CURDIR)/../../include/uapi/linux/iio/types.h $@
|
||||
|
||||
iio_generic_buffer: iio_generic_buffer.o iio_utils.o
|
||||
prepare: $(OUTPUT)include/linux/iio
|
||||
|
||||
%.o: %.c iio_utils.h
|
||||
LSIIO_IN := $(OUTPUT)lsiio-in.o
|
||||
$(LSIIO_IN): prepare FORCE
|
||||
$(Q)$(MAKE) $(build)=lsiio
|
||||
$(OUTPUT)lsiio: $(LSIIO_IN)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||
|
||||
install:
|
||||
- mkdir -p $(INSTALL_ROOT)/$(BINDIR)
|
||||
- $(INSTALL_PROGRAM) "iio_event_monitor" "$(INSTALL_ROOT)/$(BINDIR)/iio_event_monitor"
|
||||
- $(INSTALL_PROGRAM) "lsiio" "$(INSTALL_ROOT)/$(BINDIR)/lsiio"
|
||||
- $(INSTALL_PROGRAM) "iio_generic_buffer" "$(INSTALL_ROOT)/$(BINDIR)/iio_generic_buffer"
|
||||
IIO_EVENT_MONITOR_IN := $(OUTPUT)iio_event_monitor-in.o
|
||||
$(IIO_EVENT_MONITOR_IN): prepare FORCE
|
||||
$(Q)$(MAKE) $(build)=iio_event_monitor
|
||||
$(OUTPUT)iio_event_monitor: $(IIO_EVENT_MONITOR_IN)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||
|
||||
uninstall:
|
||||
$(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/iio_event_monitor"
|
||||
$(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/lsiio"
|
||||
$(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/iio_generic_buffer"
|
||||
IIO_GENERIC_BUFFER_IN := $(OUTPUT)iio_generic_buffer-in.o
|
||||
$(IIO_GENERIC_BUFFER_IN): prepare FORCE
|
||||
$(Q)$(MAKE) $(build)=iio_generic_buffer
|
||||
$(OUTPUT)iio_generic_buffer: $(IIO_GENERIC_BUFFER_IN)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o iio_event_monitor lsiio iio_generic_buffer
|
||||
rm -f $(ALL_PROGRAMS)
|
||||
rm -rf $(OUTPUT)include/linux/iio
|
||||
find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
|
||||
|
||||
install: $(ALL_PROGRAMS)
|
||||
install -d -m 755 $(DESTDIR)$(bindir); \
|
||||
for program in $(ALL_PROGRAMS); do \
|
||||
install $$program $(DESTDIR)$(bindir); \
|
||||
done
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: all install clean FORCE prepare
|
||||
|
|
Loading…
Reference in New Issue