diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-07 13:31:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-07 13:31:29 -0700 |
commit | e0dccbdf5ac7ccb9da5612100dedba302f3ebcfe (patch) | |
tree | 0bdabbf13844ae18da61bc060348850a8038f0ba /drivers/iio/imu/adis16480.c | |
parent | cf482a49af564a3044de3178ea28f10ad5921b38 (diff) | |
parent | e2a5be107f52cefb9010ccae6f569c3ddaa954cc (diff) | |
download | kernel_replicant_linux-e0dccbdf5ac7ccb9da5612100dedba302f3ebcfe.tar.gz kernel_replicant_linux-e0dccbdf5ac7ccb9da5612100dedba302f3ebcfe.tar.bz2 kernel_replicant_linux-e0dccbdf5ac7ccb9da5612100dedba302f3ebcfe.zip |
Merge tag 'staging-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging / IIO driver updates from Greg KH:
"Here is the big staging and iio driver update for 5.2-rc1.
Lots of tiny fixes all over the staging and IIO driver trees here,
along with some new IIO drivers.
The "counter" subsystem was added in here as well, as it is needed by
the IIO drivers and subsystem.
Also we ended up deleting two drivers, making this pull request remove
a few hundred thousand lines of code, always a nice thing to see. Both
of the drivers removed have been replaced with "real" drivers in their
various subsystem directories, and they will be coming to you from
those locations during this merge window.
There are some core vt/selection changes in here, that was due to some
cleanups needed for the speakup fixes. Those have all been acked by
the various subsystem maintainers (i.e. me), so those are ok.
We also added a few new drivers, for some odd hardware, giving new
developers plenty to work on with basic coding style cleanups to come
in the near future.
Other than that, nothing unusual here.
All of these have been in linux-next for a while with no reported
issues, other than an odd gcc warning for one of the new drivers that
should be fixed up soon"
[ I fixed up the warning myself - Linus ]
* tag 'staging-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (663 commits)
staging: kpc2000: kpc_spi: Fix build error for {read,write}q
Staging: rtl8192e: Remove extra space before break statement
Staging: rtl8192u: ieee80211: Fix if-else indentation warning
Staging: rtl8192u: ieee80211: Fix indentation errors by removing extra spaces
staging: most: cdev: fix chrdev_region leak in mod_exit
staging: wlan-ng: Fix improper SPDX comment style
staging: rtl8192u: ieee80211: Resolve ERROR reported by checkpatch
staging: vc04_services: bcm2835-camera: Compress two lines into one line
staging: rtl8723bs: core: Use !x in place of NULL comparison.
staging: rtl8723bs: core: Prefer using the BIT Macro.
staging: fieldbus: anybus-s: fix wait_for_completion_timeout return handling
staging: kpc2000: fix up build problems with readq()
staging: rtlwifi: move remaining phydm .h files
staging: rtlwifi: strip down phydm .h files
staging: rtlwifi: delete the staging driver
staging: fieldbus: anybus-s: rename bus id field to avoid confusion
staging: fieldbus: anybus-s: keep device bus id in bus endianness
Staging: sm750fb: Change *array into *const array
staging: rtl8192u: ieee80211: Fix spelling mistake
staging: rtl8192u: ieee80211: Replace bit shifting with BIT macro
...
Diffstat (limited to 'drivers/iio/imu/adis16480.c')
-rw-r--r-- | drivers/iio/imu/adis16480.c | 435 |
1 files changed, 417 insertions, 18 deletions
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index a27fe208f3ae..ab137c1bbe7b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -9,6 +9,9 @@ * */ +#include <linux/clk.h> +#include <linux/bitfield.h> +#include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mutex.h> @@ -97,6 +100,12 @@ #define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) #define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) +/* + * External clock scaling in PPS mode. + * Available only for ADIS1649x devices + */ +#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10) + #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) /* Each filter coefficent bank spans two pages */ @@ -107,6 +116,20 @@ #define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) #define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) +/* ADIS16480_REG_FNCTIO_CTRL */ +#define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0) +#define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x) +#define ADIS16480_DRDY_POL_MSK BIT(2) +#define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x) +#define ADIS16480_DRDY_EN_MSK BIT(3) +#define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x) +#define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4) +#define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x) +#define ADIS16480_SYNC_EN_MSK BIT(7) +#define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x) +#define ADIS16480_SYNC_MODE_MSK BIT(8) +#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x) + struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; @@ -114,12 +137,40 @@ struct adis16480_chip_info { unsigned int gyro_max_scale; unsigned int accel_max_val; unsigned int accel_max_scale; + unsigned int temp_scale; + unsigned int int_clk; + unsigned int max_dec_rate; + const unsigned int *filter_freqs; + bool has_pps_clk_mode; +}; + +enum adis16480_int_pin { + ADIS16480_PIN_DIO1, + ADIS16480_PIN_DIO2, + ADIS16480_PIN_DIO3, + ADIS16480_PIN_DIO4 +}; + +enum adis16480_clock_mode { + ADIS16480_CLK_SYNC, + ADIS16480_CLK_PPS, + ADIS16480_CLK_INT }; struct adis16480 { const struct adis16480_chip_info *chip_info; struct adis adis; + struct clk *ext_clk; + enum adis16480_clock_mode clk_mode; + unsigned int clk_freq; +}; + +static const char * const adis16480_int_pin_names[4] = { + [ADIS16480_PIN_DIO1] = "DIO1", + [ADIS16480_PIN_DIO2] = "DIO2", + [ADIS16480_PIN_DIO3] = "DIO3", + [ADIS16480_PIN_DIO4] = "DIO4", }; #ifdef CONFIG_DEBUG_FS @@ -268,20 +319,34 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev) static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) { struct adis16480 *st = iio_priv(indio_dev); - unsigned int t; + unsigned int t, reg; t = val * 1000 + val2 / 1000; if (t <= 0) return -EINVAL; - t = 2460000 / t; - if (t > 2048) - t = 2048; + /* + * When using PPS mode, the rate of data collection is equal to the + * product of the external clock frequency and the scale factor in the + * SYNC_SCALE register. + * When using sync mode, or internal clock, the output data rate is + * equal with the clock frequency divided by DEC_RATE + 1. + */ + if (st->clk_mode == ADIS16480_CLK_PPS) { + t = t / st->clk_freq; + reg = ADIS16495_REG_SYNC_SCALE; + } else { + t = st->clk_freq / t; + reg = ADIS16480_REG_DEC_RATE; + } + + if (t > st->chip_info->max_dec_rate) + t = st->chip_info->max_dec_rate; - if (t != 0) + if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS)) t--; - return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); + return adis_write_reg_16(&st->adis, reg, t); } static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) @@ -290,12 +355,29 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) uint16_t t; int ret; unsigned freq; + unsigned int reg; - ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); + if (st->clk_mode == ADIS16480_CLK_PPS) + reg = ADIS16495_REG_SYNC_SCALE; + else + reg = ADIS16480_REG_DEC_RATE; + + ret = adis_read_reg_16(&st->adis, reg, &t); if (ret < 0) return ret; - freq = 2460000 / (t + 1); + /* + * When using PPS mode, the rate of data collection is equal to the + * product of the external clock frequency and the scale factor in the + * SYNC_SCALE register. + * When using sync mode, or internal clock, the output data rate is + * equal with the clock frequency divided by DEC_RATE + 1. + */ + if (st->clk_mode == ADIS16480_CLK_PPS) + freq = st->clk_freq * t; + else + freq = st->clk_freq / (t + 1); + *val = freq / 1000; *val2 = (freq % 1000) * 1000; @@ -425,6 +507,13 @@ static const unsigned int adis16480_def_filter_freqs[] = { 63, }; +static const unsigned int adis16495_def_filter_freqs[] = { + 300, + 100, + 300, + 100, +}; + static const unsigned int ad16480_filter_data[][2] = { [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 }, [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 }, @@ -456,7 +545,7 @@ static int adis16480_get_filter_freq(struct iio_dev *indio_dev, if (!(val & enable_mask)) *freq = 0; else - *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3]; + *freq = st->chip_info->filter_freqs[(val >> offset) & 0x3]; return IIO_VAL_INT; } @@ -483,10 +572,10 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, val &= ~enable_mask; } else { best_freq = 0; - best_diff = 310; + best_diff = st->chip_info->filter_freqs[0]; for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { - if (adis16480_def_filter_freqs[i] >= freq) { - diff = adis16480_def_filter_freqs[i] - freq; + if (st->chip_info->filter_freqs[i] >= freq) { + diff = st->chip_info->filter_freqs[i] - freq; if (diff < best_diff) { best_diff = diff; best_freq = i; @@ -506,6 +595,7 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { struct adis16480 *st = iio_priv(indio_dev); + unsigned int temp; switch (info) { case IIO_CHAN_INFO_RAW: @@ -525,8 +615,13 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, *val2 = 100; /* 0.0001 gauss */ return IIO_VAL_INT_PLUS_MICRO; case IIO_TEMP: - *val = 5; - *val2 = 650000; /* 5.65 milli degree Celsius */ + /* + * +85 degrees Celsius = temp_max_scale + * +25 degrees Celsius = 0 + * LSB, 25 degrees Celsius = 60 / temp_max_scale + */ + *val = st->chip_info->temp_scale / 1000; + *val2 = (st->chip_info->temp_scale % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_PRESSURE: *val = 0; @@ -537,7 +632,8 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, } case IIO_CHAN_INFO_OFFSET: /* Only the temperature channel has a offset */ - *val = 4425; /* 25 degree Celsius = 0x0000 */ + temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */ + *val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale); return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: return adis16480_get_calibbias(indio_dev, chan, val); @@ -678,6 +774,12 @@ enum adis16480_variant { ADIS16480, ADIS16485, ADIS16488, + ADIS16495_1, + ADIS16495_2, + ADIS16495_3, + ADIS16497_1, + ADIS16497_2, + ADIS16497_3, }; static const struct adis16480_chip_info adis16480_chip_info[] = { @@ -693,6 +795,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 300, .accel_max_val = IIO_M_S_2_TO_G(21973), .accel_max_scale = 18, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, }, [ADIS16480] = { .channels = adis16480_channels, @@ -701,6 +807,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 450, .accel_max_val = IIO_M_S_2_TO_G(12500), .accel_max_scale = 10, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, }, [ADIS16485] = { .channels = adis16485_channels, @@ -709,6 +819,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 450, .accel_max_val = IIO_M_S_2_TO_G(20000), .accel_max_scale = 5, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, }, [ADIS16488] = { .channels = adis16480_channels, @@ -717,6 +831,88 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .gyro_max_scale = 450, .accel_max_val = IIO_M_S_2_TO_G(22500), .accel_max_scale = 18, + .temp_scale = 5650, /* 5.65 milli degree Celsius */ + .int_clk = 2460000, + .max_dec_rate = 2048, + .filter_freqs = adis16480_def_filter_freqs, + }, + [ADIS16495_1] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 125, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 8, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16495_2] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(18000), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 8, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16495_3] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 2000, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 8, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16497_1] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 125, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 40, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16497_2] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(18000), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 40, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, + }, + [ADIS16497_3] = { + .channels = adis16485_channels, + .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(20000), + .gyro_max_scale = 2000, + .accel_max_val = IIO_M_S_2_TO_G(32000), + .accel_max_scale = 40, + .temp_scale = 12500, /* 12.5 milli degree Celsius */ + .int_clk = 4250000, + .max_dec_rate = 4250, + .filter_freqs = adis16495_def_filter_freqs, + .has_pps_clk_mode = true, }, }; @@ -741,8 +937,17 @@ static int adis16480_stop_device(struct iio_dev *indio_dev) static int adis16480_enable_irq(struct adis *adis, bool enable) { - return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, - enable ? BIT(3) : 0); + uint16_t val; + int ret; + + ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); + if (ret < 0) + return ret; + + val &= ~ADIS16480_DRDY_EN_MSK; + val |= ADIS16480_DRDY_EN(enable); + + return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); } static int adis16480_initial_setup(struct iio_dev *indio_dev) @@ -826,6 +1031,156 @@ static const struct adis_data adis16480_data = { .enable_irq = adis16480_enable_irq, }; +static int adis16480_config_irq_pin(struct device_node *of_node, + struct adis16480 *st) +{ + struct irq_data *desc; + enum adis16480_int_pin pin; + unsigned int irq_type; + uint16_t val; + int i, irq = 0; + + desc = irq_get_irq_data(st->adis.spi->irq); + if (!desc) { + dev_err(&st->adis.spi->dev, "Could not find IRQ %d\n", irq); + return -EINVAL; + } + + /* Disable data ready since the default after reset is on */ + val = ADIS16480_DRDY_EN(0); + + /* + * Get the interrupt from the devicetre by reading the interrupt-names + * property. If it is not specified, use DIO1 pin as default. + * According to the datasheet, the factory default assigns DIO2 as data + * ready signal. However, in the previous versions of the driver, DIO1 + * pin was used. So, we should leave it as is since some devices might + * be expecting the interrupt on the wrong physical pin. + */ + pin = ADIS16480_PIN_DIO1; + for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { + irq = of_irq_get_byname(of_node, adis16480_int_pin_names[i]); + if (irq > 0) { + pin = i; + break; + } + } + + val |= ADIS16480_DRDY_SEL(pin); + + /* + * Get the interrupt line behaviour. The data ready polarity can be + * configured as positive or negative, corresponding to + * IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING respectively. + */ + irq_type = irqd_get_trigger_type(desc); + if (irq_type == IRQF_TRIGGER_RISING) { /* Default */ + val |= ADIS16480_DRDY_POL(1); + } else if (irq_type == IRQF_TRIGGER_FALLING) { + val |= ADIS16480_DRDY_POL(0); + } else { + dev_err(&st->adis.spi->dev, + "Invalid interrupt type 0x%x specified\n", irq_type); + return -EINVAL; + } + /* Write the data ready configuration to the FNCTIO_CTRL register */ + return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); +} + +static int adis16480_of_get_ext_clk_pin(struct adis16480 *st, + struct device_node *of_node) +{ + const char *ext_clk_pin; + enum adis16480_int_pin pin; + int i; + + pin = ADIS16480_PIN_DIO2; + if (of_property_read_string(of_node, "adi,ext-clk-pin", &ext_clk_pin)) + goto clk_input_not_found; + + for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { + if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0) + return i; + } + +clk_input_not_found: + dev_info(&st->adis.spi->dev, + "clk input line not specified, using DIO2\n"); + return pin; +} + +static int adis16480_ext_clk_config(struct adis16480 *st, + struct device_node *of_node, + bool enable) +{ + unsigned int mode, mask; + enum adis16480_int_pin pin; + uint16_t val; + int ret; + + ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val); + if (ret < 0) + return ret; + + pin = adis16480_of_get_ext_clk_pin(st, of_node); + /* + * Each DIOx pin supports only one function at a time. When a single pin + * has two assignments, the enable bit for a lower priority function + * automatically resets to zero (disabling the lower priority function). + */ + if (pin == ADIS16480_DRDY_SEL(val)) + dev_warn(&st->adis.spi->dev, + "DIO%x pin supports only one function at a time\n", + pin + 1); + + mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin); + mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK; + /* Only ADIS1649x devices support pps ext clock mode */ + if (st->chip_info->has_pps_clk_mode) { + mode |= ADIS16480_SYNC_MODE(st->clk_mode); + mask |= ADIS16480_SYNC_MODE_MSK; + } + + val &= ~mask; + val |= mode; + + ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); + if (ret < 0) + return ret; + + return clk_prepare_enable(st->ext_clk); +} + +static int adis16480_get_ext_clocks(struct adis16480 *st) +{ + st->clk_mode = ADIS16480_CLK_INT; + st->ext_clk = devm_clk_get(&st->adis.spi->dev, "sync"); + if (!IS_ERR_OR_NULL(st->ext_clk)) { + st->clk_mode = ADIS16480_CLK_SYNC; + return 0; + } + + if (PTR_ERR(st->ext_clk) != -ENOENT) { + dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); + return PTR_ERR(st->ext_clk); + } + + if (st->chip_info->has_pps_clk_mode) { + st->ext_clk = devm_clk_get(&st->adis.spi->dev, "pps"); + if (!IS_ERR_OR_NULL(st->ext_clk)) { + st->clk_mode = ADIS16480_CLK_PPS; + return 0; + } + + if (PTR_ERR(st->ext_clk) != -ENOENT) { + dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); + return PTR_ERR(st->ext_clk); + } + } + + return 0; +} + static int adis16480_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); @@ -853,10 +1208,29 @@ static int adis16480_probe(struct spi_device *spi) if (ret) return ret; - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + ret = adis16480_config_irq_pin(spi->dev.of_node, st); + if (ret) + return ret; + + ret = adis16480_get_ext_clocks(st); if (ret) return ret; + if (!IS_ERR_OR_NULL(st->ext_clk)) { + ret = adis16480_ext_clk_config(st, spi->dev.of_node, true); + if (ret) + return ret; + + st->clk_freq = clk_get_rate(st->ext_clk); + st->clk_freq *= 1000; /* micro */ + } else { + st->clk_freq = st->chip_info->int_clk; + } + + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + if (ret) + goto error_clk_disable_unprepare; + ret = adis16480_initial_setup(indio_dev); if (ret) goto error_cleanup_buffer; @@ -873,6 +1247,8 @@ error_stop_device: adis16480_stop_device(indio_dev); error_cleanup_buffer: adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); +error_clk_disable_unprepare: + clk_disable_unprepare(st->ext_clk); return ret; } @@ -885,6 +1261,7 @@ static int adis16480_remove(struct spi_device *spi) adis16480_stop_device(indio_dev); adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); + clk_disable_unprepare(st->ext_clk); return 0; } @@ -894,13 +1271,35 @@ static const struct spi_device_id adis16480_ids[] = { { "adis16480", ADIS16480 }, { "adis16485", ADIS16485 }, { "adis16488", ADIS16488 }, + { "adis16495-1", ADIS16495_1 }, + { "adis16495-2", ADIS16495_2 }, + { "adis16495-3", ADIS16495_3 }, + { "adis16497-1", ADIS16497_1 }, + { "adis16497-2", ADIS16497_2 }, + { "adis16497-3", ADIS16497_3 }, { } }; MODULE_DEVICE_TABLE(spi, adis16480_ids); +static const struct of_device_id adis16480_of_match[] = { + { .compatible = "adi,adis16375" }, + { .compatible = "adi,adis16480" }, + { .compatible = "adi,adis16485" }, + { .compatible = "adi,adis16488" }, + { .compatible = "adi,adis16495-1" }, + { .compatible = "adi,adis16495-2" }, + { .compatible = "adi,adis16495-3" }, + { .compatible = "adi,adis16497-1" }, + { .compatible = "adi,adis16497-2" }, + { .compatible = "adi,adis16497-3" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adis16480_of_match); + static struct spi_driver adis16480_driver = { .driver = { .name = "adis16480", + .of_match_table = adis16480_of_match, }, .id_table = adis16480_ids, .probe = adis16480_probe, |