1cf890fe8SJonathan Cameron // SPDX-License-Identifier: GPL-2.0 2cf890fe8SJonathan Cameron /* 3cf890fe8SJonathan Cameron * AD7280A Lithium Ion Battery Monitoring System 4cf890fe8SJonathan Cameron * 5cf890fe8SJonathan Cameron * Copyright 2011 Analog Devices Inc. 6cf890fe8SJonathan Cameron */ 7cf890fe8SJonathan Cameron 8cf890fe8SJonathan Cameron #include <linux/bitfield.h> 9cf890fe8SJonathan Cameron #include <linux/bits.h> 10cf890fe8SJonathan Cameron #include <linux/crc8.h> 11cf890fe8SJonathan Cameron #include <linux/delay.h> 12cf890fe8SJonathan Cameron #include <linux/device.h> 13cf890fe8SJonathan Cameron #include <linux/err.h> 14cf890fe8SJonathan Cameron #include <linux/interrupt.h> 15cf890fe8SJonathan Cameron #include <linux/kernel.h> 16cf890fe8SJonathan Cameron #include <linux/module.h> 17cf890fe8SJonathan Cameron #include <linux/mod_devicetable.h> 18cf890fe8SJonathan Cameron #include <linux/mutex.h> 19cf890fe8SJonathan Cameron #include <linux/slab.h> 20cf890fe8SJonathan Cameron #include <linux/sysfs.h> 21cf890fe8SJonathan Cameron #include <linux/spi/spi.h> 22cf890fe8SJonathan Cameron 23cf890fe8SJonathan Cameron #include <linux/iio/events.h> 24cf890fe8SJonathan Cameron #include <linux/iio/iio.h> 25cf890fe8SJonathan Cameron 26cf890fe8SJonathan Cameron /* Registers */ 27cf890fe8SJonathan Cameron 28cf890fe8SJonathan Cameron #define AD7280A_CELL_VOLTAGE_1_REG 0x0 /* D11 to D0, Read only */ 29cf890fe8SJonathan Cameron #define AD7280A_CELL_VOLTAGE_2_REG 0x1 /* D11 to D0, Read only */ 30cf890fe8SJonathan Cameron #define AD7280A_CELL_VOLTAGE_3_REG 0x2 /* D11 to D0, Read only */ 31cf890fe8SJonathan Cameron #define AD7280A_CELL_VOLTAGE_4_REG 0x3 /* D11 to D0, Read only */ 32cf890fe8SJonathan Cameron #define AD7280A_CELL_VOLTAGE_5_REG 0x4 /* D11 to D0, Read only */ 33cf890fe8SJonathan Cameron #define AD7280A_CELL_VOLTAGE_6_REG 0x5 /* D11 to D0, Read only */ 34cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_1_REG 0x6 /* D11 to D0, Read only */ 35cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_2_REG 0x7 /* D11 to D0, Read only */ 36cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_3_REG 0x8 /* D11 to D0, Read only */ 37cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_4_REG 0x9 /* D11 to D0, Read only */ 38cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_5_REG 0xA /* D11 to D0, Read only */ 39cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_6_REG 0xB /* D11 to D0, Read only */ 40cf890fe8SJonathan Cameron #define AD7280A_SELF_TEST_REG 0xC /* D11 to D0, Read only */ 41cf890fe8SJonathan Cameron 42cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_REG 0xD /* D15 to D8, Read/write */ 43cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_INPUT_MSK GENMASK(7, 6) 44cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_INPUT_ALL 0 45cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_INPUT_6CELL_AUX1_3_5 1 46cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_INPUT_6CELL 2 47cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST 3 48cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_RREAD_MSK GENMASK(5, 4) 49cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_RREAD_ALL 0 50cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_RREAD_6CELL_AUX1_3_5 1 51cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_RREAD_6CELL 2 52cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_RREAD_NO 3 53cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_START_MSK BIT(3) 54cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_START_CNVST 0 55cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_START_CS 1 56cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_AVG_MSK GENMASK(2, 1) 57cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_AVG_DIS 0 58cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_AVG_2 1 59cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_AVG_4 2 60cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_CONV_AVG_8 3 61cf890fe8SJonathan Cameron #define AD7280A_CTRL_HB_PWRDN_SW BIT(0) 62cf890fe8SJonathan Cameron 63cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_REG 0xE /* D7 to D0, Read/write */ 64cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_SWRST_MSK BIT(7) 65cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_ACQ_TIME_MSK GENMASK(6, 5) 66cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_ACQ_TIME_400ns 0 67cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_ACQ_TIME_800ns 1 68cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_ACQ_TIME_1200ns 2 69cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_ACQ_TIME_1600ns 3 70cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_MUST_SET BIT(4) 71cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_THERMISTOR_MSK BIT(3) 72cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK BIT(2) 73cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_INC_DEV_ADDR_MSK BIT(1) 74cf890fe8SJonathan Cameron #define AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK BIT(0) 75cf890fe8SJonathan Cameron 76cf890fe8SJonathan Cameron #define AD7280A_CELL_OVERVOLTAGE_REG 0xF /* D7 to D0, Read/write */ 77cf890fe8SJonathan Cameron #define AD7280A_CELL_UNDERVOLTAGE_REG 0x10 /* D7 to D0, Read/write */ 78cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_OVERVOLTAGE_REG 0x11 /* D7 to D0, Read/write */ 79cf890fe8SJonathan Cameron #define AD7280A_AUX_ADC_UNDERVOLTAGE_REG 0x12 /* D7 to D0, Read/write */ 80cf890fe8SJonathan Cameron 81cf890fe8SJonathan Cameron #define AD7280A_ALERT_REG 0x13 /* D7 to D0, Read/write */ 82cf890fe8SJonathan Cameron #define AD7280A_ALERT_REMOVE_MSK GENMASK(3, 0) 83cf890fe8SJonathan Cameron #define AD7280A_ALERT_REMOVE_AUX5 BIT(0) 84cf890fe8SJonathan Cameron #define AD7280A_ALERT_REMOVE_AUX3_AUX5 BIT(1) 85cf890fe8SJonathan Cameron #define AD7280A_ALERT_REMOVE_VIN5 BIT(2) 86cf890fe8SJonathan Cameron #define AD7280A_ALERT_REMOVE_VIN4_VIN5 BIT(3) 87cf890fe8SJonathan Cameron #define AD7280A_ALERT_GEN_STATIC_HIGH BIT(6) 88cf890fe8SJonathan Cameron #define AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN (BIT(7) | BIT(6)) 89cf890fe8SJonathan Cameron 90cf890fe8SJonathan Cameron #define AD7280A_CELL_BALANCE_REG 0x14 /* D7 to D0, Read/write */ 91cf890fe8SJonathan Cameron #define AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK GENMASK(7, 2) 92cf890fe8SJonathan Cameron #define AD7280A_CB1_TIMER_REG 0x15 /* D7 to D0, Read/write */ 93cf890fe8SJonathan Cameron #define AD7280A_CB_TIMER_VAL_MSK GENMASK(7, 3) 94cf890fe8SJonathan Cameron #define AD7280A_CB2_TIMER_REG 0x16 /* D7 to D0, Read/write */ 95cf890fe8SJonathan Cameron #define AD7280A_CB3_TIMER_REG 0x17 /* D7 to D0, Read/write */ 96cf890fe8SJonathan Cameron #define AD7280A_CB4_TIMER_REG 0x18 /* D7 to D0, Read/write */ 97cf890fe8SJonathan Cameron #define AD7280A_CB5_TIMER_REG 0x19 /* D7 to D0, Read/write */ 98cf890fe8SJonathan Cameron #define AD7280A_CB6_TIMER_REG 0x1A /* D7 to D0, Read/write */ 99cf890fe8SJonathan Cameron #define AD7280A_PD_TIMER_REG 0x1B /* D7 to D0, Read/write */ 100cf890fe8SJonathan Cameron #define AD7280A_READ_REG 0x1C /* D7 to D0, Read/write */ 101cf890fe8SJonathan Cameron #define AD7280A_READ_ADDR_MSK GENMASK(7, 2) 102cf890fe8SJonathan Cameron #define AD7280A_CNVST_CTRL_REG 0x1D /* D7 to D0, Read/write */ 103cf890fe8SJonathan Cameron 104cf890fe8SJonathan Cameron /* Transfer fields */ 105cf890fe8SJonathan Cameron #define AD7280A_TRANS_WRITE_DEVADDR_MSK GENMASK(31, 27) 106cf890fe8SJonathan Cameron #define AD7280A_TRANS_WRITE_ADDR_MSK GENMASK(26, 21) 107cf890fe8SJonathan Cameron #define AD7280A_TRANS_WRITE_VAL_MSK GENMASK(20, 13) 108cf890fe8SJonathan Cameron #define AD7280A_TRANS_WRITE_ALL_MSK BIT(12) 109cf890fe8SJonathan Cameron #define AD7280A_TRANS_WRITE_CRC_MSK GENMASK(10, 3) 110cf890fe8SJonathan Cameron #define AD7280A_TRANS_WRITE_RES_PATTERN 0x2 111cf890fe8SJonathan Cameron 112cf890fe8SJonathan Cameron /* Layouts differ for channel vs other registers */ 113cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_DEVADDR_MSK GENMASK(31, 27) 114cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_CONV_CHANADDR_MSK GENMASK(26, 23) 115cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_CONV_DATA_MSK GENMASK(22, 11) 116cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_REG_REGADDR_MSK GENMASK(26, 21) 117cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_REG_DATA_MSK GENMASK(20, 13) 118cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_WRITE_ACK_MSK BIT(10) 119cf890fe8SJonathan Cameron #define AD7280A_TRANS_READ_CRC_MSK GENMASK(9, 2) 120cf890fe8SJonathan Cameron 121cf890fe8SJonathan Cameron /* Magic value used to indicate this special case */ 122cf890fe8SJonathan Cameron #define AD7280A_ALL_CELLS (0xAD << 16) 123cf890fe8SJonathan Cameron 124cf890fe8SJonathan Cameron #define AD7280A_MAX_SPI_CLK_HZ 700000 /* < 1MHz */ 125cf890fe8SJonathan Cameron #define AD7280A_MAX_CHAIN 8 126cf890fe8SJonathan Cameron #define AD7280A_CELLS_PER_DEV 6 127cf890fe8SJonathan Cameron #define AD7280A_BITS 12 128cf890fe8SJonathan Cameron #define AD7280A_NUM_CH (AD7280A_AUX_ADC_6_REG - \ 129cf890fe8SJonathan Cameron AD7280A_CELL_VOLTAGE_1_REG + 1) 130cf890fe8SJonathan Cameron 131cf890fe8SJonathan Cameron #define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ 132cf890fe8SJonathan Cameron (c)) 133cf890fe8SJonathan Cameron #define AD7280A_CALC_TEMP_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ 134cf890fe8SJonathan Cameron (c) - AD7280A_CELLS_PER_DEV) 135cf890fe8SJonathan Cameron 136cf890fe8SJonathan Cameron #define AD7280A_DEVADDR_MASTER 0 137cf890fe8SJonathan Cameron #define AD7280A_DEVADDR_ALL 0x1F 138cf890fe8SJonathan Cameron 139cf890fe8SJonathan Cameron static const unsigned short ad7280a_n_avg[4] = {1, 2, 4, 8}; 140cf890fe8SJonathan Cameron static const unsigned short ad7280a_t_acq_ns[4] = {470, 1030, 1510, 1945}; 141cf890fe8SJonathan Cameron 142cf890fe8SJonathan Cameron /* 5-bit device address is sent LSB first */ 143cf890fe8SJonathan Cameron static unsigned int ad7280a_devaddr(unsigned int addr) 144cf890fe8SJonathan Cameron { 145cf890fe8SJonathan Cameron return ((addr & 0x1) << 4) | 146cf890fe8SJonathan Cameron ((addr & 0x2) << 2) | 147cf890fe8SJonathan Cameron (addr & 0x4) | 148cf890fe8SJonathan Cameron ((addr & 0x8) >> 2) | 149cf890fe8SJonathan Cameron ((addr & 0x10) >> 4); 150cf890fe8SJonathan Cameron } 151cf890fe8SJonathan Cameron 152cf890fe8SJonathan Cameron /* 153cf890fe8SJonathan Cameron * During a read a valid write is mandatory. 154cf890fe8SJonathan Cameron * So writing to the highest available address (Address 0x1F) and setting the 155cf890fe8SJonathan Cameron * address all parts bit to 0 is recommended. 156cf890fe8SJonathan Cameron * So the TXVAL is AD7280A_DEVADDR_ALL + CRC 157cf890fe8SJonathan Cameron */ 158cf890fe8SJonathan Cameron #define AD7280A_READ_TXVAL 0xF800030A 159cf890fe8SJonathan Cameron 160cf890fe8SJonathan Cameron /* 161cf890fe8SJonathan Cameron * AD7280 CRC 162cf890fe8SJonathan Cameron * 163cf890fe8SJonathan Cameron * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F 164cf890fe8SJonathan Cameron */ 165cf890fe8SJonathan Cameron #define POLYNOM 0x2F 166cf890fe8SJonathan Cameron 167cf890fe8SJonathan Cameron struct ad7280_state { 168cf890fe8SJonathan Cameron struct spi_device *spi; 169cf890fe8SJonathan Cameron struct iio_chan_spec *channels; 170cf890fe8SJonathan Cameron unsigned int chain_last_alert_ignore; 171cf890fe8SJonathan Cameron bool thermistor_term_en; 172cf890fe8SJonathan Cameron int slave_num; 173cf890fe8SJonathan Cameron int scan_cnt; 174cf890fe8SJonathan Cameron int readback_delay_us; 175cf890fe8SJonathan Cameron unsigned char crc_tab[CRC8_TABLE_SIZE]; 176cf890fe8SJonathan Cameron u8 oversampling_ratio; 177cf890fe8SJonathan Cameron u8 acquisition_time; 178cf890fe8SJonathan Cameron unsigned char ctrl_lb; 179cf890fe8SJonathan Cameron unsigned char cell_threshhigh; 180cf890fe8SJonathan Cameron unsigned char cell_threshlow; 181cf890fe8SJonathan Cameron unsigned char aux_threshhigh; 182cf890fe8SJonathan Cameron unsigned char aux_threshlow; 183cf890fe8SJonathan Cameron unsigned char cb_mask[AD7280A_MAX_CHAIN]; 184cf890fe8SJonathan Cameron struct mutex lock; /* protect sensor state */ 185cf890fe8SJonathan Cameron 186cf890fe8SJonathan Cameron __be32 tx ____cacheline_aligned; 187cf890fe8SJonathan Cameron __be32 rx; 188cf890fe8SJonathan Cameron }; 189cf890fe8SJonathan Cameron 190cf890fe8SJonathan Cameron static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val) 191cf890fe8SJonathan Cameron { 192cf890fe8SJonathan Cameron unsigned char crc; 193cf890fe8SJonathan Cameron 194cf890fe8SJonathan Cameron crc = crc_tab[val >> 16 & 0xFF]; 195cf890fe8SJonathan Cameron crc = crc_tab[crc ^ (val >> 8 & 0xFF)]; 196cf890fe8SJonathan Cameron 197cf890fe8SJonathan Cameron return crc ^ (val & 0xFF); 198cf890fe8SJonathan Cameron } 199cf890fe8SJonathan Cameron 200cf890fe8SJonathan Cameron static int ad7280_check_crc(struct ad7280_state *st, unsigned int val) 201cf890fe8SJonathan Cameron { 202cf890fe8SJonathan Cameron unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10); 203cf890fe8SJonathan Cameron 204cf890fe8SJonathan Cameron if (crc != ((val >> 2) & 0xFF)) 205cf890fe8SJonathan Cameron return -EIO; 206cf890fe8SJonathan Cameron 207cf890fe8SJonathan Cameron return 0; 208cf890fe8SJonathan Cameron } 209cf890fe8SJonathan Cameron 210cf890fe8SJonathan Cameron /* 211cf890fe8SJonathan Cameron * After initiating a conversion sequence we need to wait until the conversion 212cf890fe8SJonathan Cameron * is done. The delay is typically in the range of 15..30us however depending on 213cf890fe8SJonathan Cameron * the number of devices in the daisy chain, the number of averages taken, 214cf890fe8SJonathan Cameron * conversion delays and acquisition time options it may take up to 250us, in 215cf890fe8SJonathan Cameron * this case we better sleep instead of busy wait. 216cf890fe8SJonathan Cameron */ 217cf890fe8SJonathan Cameron 218cf890fe8SJonathan Cameron static void ad7280_delay(struct ad7280_state *st) 219cf890fe8SJonathan Cameron { 220cf890fe8SJonathan Cameron if (st->readback_delay_us < 50) 221cf890fe8SJonathan Cameron udelay(st->readback_delay_us); 222cf890fe8SJonathan Cameron else 223cf890fe8SJonathan Cameron usleep_range(250, 500); 224cf890fe8SJonathan Cameron } 225cf890fe8SJonathan Cameron 226cf890fe8SJonathan Cameron static int __ad7280_read32(struct ad7280_state *st, unsigned int *val) 227cf890fe8SJonathan Cameron { 228cf890fe8SJonathan Cameron int ret; 229cf890fe8SJonathan Cameron struct spi_transfer t = { 230cf890fe8SJonathan Cameron .tx_buf = &st->tx, 231cf890fe8SJonathan Cameron .rx_buf = &st->rx, 232cf890fe8SJonathan Cameron .len = sizeof(st->tx), 233cf890fe8SJonathan Cameron }; 234cf890fe8SJonathan Cameron 235cf890fe8SJonathan Cameron st->tx = cpu_to_be32(AD7280A_READ_TXVAL); 236cf890fe8SJonathan Cameron 237cf890fe8SJonathan Cameron ret = spi_sync_transfer(st->spi, &t, 1); 238cf890fe8SJonathan Cameron if (ret) 239cf890fe8SJonathan Cameron return ret; 240cf890fe8SJonathan Cameron 241cf890fe8SJonathan Cameron *val = be32_to_cpu(st->rx); 242cf890fe8SJonathan Cameron 243cf890fe8SJonathan Cameron return 0; 244cf890fe8SJonathan Cameron } 245cf890fe8SJonathan Cameron 246cf890fe8SJonathan Cameron static int ad7280_write(struct ad7280_state *st, unsigned int devaddr, 247cf890fe8SJonathan Cameron unsigned int addr, bool all, unsigned int val) 248cf890fe8SJonathan Cameron { 249cf890fe8SJonathan Cameron unsigned int reg = FIELD_PREP(AD7280A_TRANS_WRITE_DEVADDR_MSK, devaddr) | 250cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_TRANS_WRITE_ADDR_MSK, addr) | 251cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_TRANS_WRITE_VAL_MSK, val) | 252cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_TRANS_WRITE_ALL_MSK, all); 253cf890fe8SJonathan Cameron 254cf890fe8SJonathan Cameron reg |= FIELD_PREP(AD7280A_TRANS_WRITE_CRC_MSK, 255cf890fe8SJonathan Cameron ad7280_calc_crc8(st->crc_tab, reg >> 11)); 256cf890fe8SJonathan Cameron /* Reserved b010 pattern not included crc calc */ 257cf890fe8SJonathan Cameron reg |= AD7280A_TRANS_WRITE_RES_PATTERN; 258cf890fe8SJonathan Cameron 259cf890fe8SJonathan Cameron st->tx = cpu_to_be32(reg); 260cf890fe8SJonathan Cameron 261cf890fe8SJonathan Cameron return spi_write(st->spi, &st->tx, sizeof(st->tx)); 262cf890fe8SJonathan Cameron } 263cf890fe8SJonathan Cameron 264cf890fe8SJonathan Cameron static int ad7280_read_reg(struct ad7280_state *st, unsigned int devaddr, 265cf890fe8SJonathan Cameron unsigned int addr) 266cf890fe8SJonathan Cameron { 267cf890fe8SJonathan Cameron int ret; 268cf890fe8SJonathan Cameron unsigned int tmp; 269cf890fe8SJonathan Cameron 270cf890fe8SJonathan Cameron /* turns off the read operation on all parts */ 271cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, 272cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, 273cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_INPUT_ALL) | 274cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, 275cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_RREAD_NO) | 276cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, 277cf890fe8SJonathan Cameron st->oversampling_ratio)); 278cf890fe8SJonathan Cameron if (ret) 279cf890fe8SJonathan Cameron return ret; 280cf890fe8SJonathan Cameron 281cf890fe8SJonathan Cameron /* turns on the read operation on the addressed part */ 282cf890fe8SJonathan Cameron ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, 283cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, 284cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_INPUT_ALL) | 285cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, 286cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_RREAD_ALL) | 287cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, 288cf890fe8SJonathan Cameron st->oversampling_ratio)); 289cf890fe8SJonathan Cameron if (ret) 290cf890fe8SJonathan Cameron return ret; 291cf890fe8SJonathan Cameron 292cf890fe8SJonathan Cameron /* Set register address on the part to be read from */ 293cf890fe8SJonathan Cameron ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, 294cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); 295cf890fe8SJonathan Cameron if (ret) 296cf890fe8SJonathan Cameron return ret; 297cf890fe8SJonathan Cameron 298cf890fe8SJonathan Cameron ret = __ad7280_read32(st, &tmp); 299cf890fe8SJonathan Cameron if (ret) 300cf890fe8SJonathan Cameron return ret; 301cf890fe8SJonathan Cameron 302cf890fe8SJonathan Cameron if (ad7280_check_crc(st, tmp)) 303cf890fe8SJonathan Cameron return -EIO; 304cf890fe8SJonathan Cameron 305cf890fe8SJonathan Cameron if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || 306cf890fe8SJonathan Cameron (FIELD_GET(AD7280A_TRANS_READ_REG_REGADDR_MSK, tmp) != addr)) 307cf890fe8SJonathan Cameron return -EFAULT; 308cf890fe8SJonathan Cameron 309cf890fe8SJonathan Cameron return FIELD_GET(AD7280A_TRANS_READ_REG_DATA_MSK, tmp); 310cf890fe8SJonathan Cameron } 311cf890fe8SJonathan Cameron 312cf890fe8SJonathan Cameron static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr, 313cf890fe8SJonathan Cameron unsigned int addr) 314cf890fe8SJonathan Cameron { 315cf890fe8SJonathan Cameron int ret; 316cf890fe8SJonathan Cameron unsigned int tmp; 317cf890fe8SJonathan Cameron 318cf890fe8SJonathan Cameron ret = ad7280_write(st, devaddr, AD7280A_READ_REG, 0, 319cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_READ_ADDR_MSK, addr)); 320cf890fe8SJonathan Cameron if (ret) 321cf890fe8SJonathan Cameron return ret; 322cf890fe8SJonathan Cameron 323cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, 324cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, 325cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_INPUT_ALL) | 326cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, 327cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_RREAD_NO) | 328cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, 329cf890fe8SJonathan Cameron st->oversampling_ratio)); 330cf890fe8SJonathan Cameron if (ret) 331cf890fe8SJonathan Cameron return ret; 332cf890fe8SJonathan Cameron 333cf890fe8SJonathan Cameron ret = ad7280_write(st, devaddr, AD7280A_CTRL_HB_REG, 0, 334cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, 335cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_INPUT_ALL) | 336cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, 337cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_RREAD_ALL) | 338cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, 339cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_START_CS) | 340cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, 341cf890fe8SJonathan Cameron st->oversampling_ratio)); 342cf890fe8SJonathan Cameron if (ret) 343cf890fe8SJonathan Cameron return ret; 344cf890fe8SJonathan Cameron 345cf890fe8SJonathan Cameron ad7280_delay(st); 346cf890fe8SJonathan Cameron 347cf890fe8SJonathan Cameron ret = __ad7280_read32(st, &tmp); 348cf890fe8SJonathan Cameron if (ret) 349cf890fe8SJonathan Cameron return ret; 350cf890fe8SJonathan Cameron 351cf890fe8SJonathan Cameron if (ad7280_check_crc(st, tmp)) 352cf890fe8SJonathan Cameron return -EIO; 353cf890fe8SJonathan Cameron 354cf890fe8SJonathan Cameron if ((FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, tmp) != devaddr) || 355cf890fe8SJonathan Cameron (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) != addr)) 356cf890fe8SJonathan Cameron return -EFAULT; 357cf890fe8SJonathan Cameron 358cf890fe8SJonathan Cameron return FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); 359cf890fe8SJonathan Cameron } 360cf890fe8SJonathan Cameron 361cf890fe8SJonathan Cameron static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt, 362cf890fe8SJonathan Cameron unsigned int *array) 363cf890fe8SJonathan Cameron { 364cf890fe8SJonathan Cameron int i, ret; 365cf890fe8SJonathan Cameron unsigned int tmp, sum = 0; 366cf890fe8SJonathan Cameron 367cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, 368cf890fe8SJonathan Cameron AD7280A_CELL_VOLTAGE_1_REG << 2); 369cf890fe8SJonathan Cameron if (ret) 370cf890fe8SJonathan Cameron return ret; 371cf890fe8SJonathan Cameron 372cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, 373cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_INPUT_MSK, 374cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_INPUT_ALL) | 375cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_RREAD_MSK, 376cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_RREAD_ALL) | 377cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_START_MSK, 378cf890fe8SJonathan Cameron AD7280A_CTRL_HB_CONV_START_CS) | 379cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, 380cf890fe8SJonathan Cameron st->oversampling_ratio)); 381cf890fe8SJonathan Cameron if (ret) 382cf890fe8SJonathan Cameron return ret; 383cf890fe8SJonathan Cameron 384cf890fe8SJonathan Cameron ad7280_delay(st); 385cf890fe8SJonathan Cameron 386cf890fe8SJonathan Cameron for (i = 0; i < cnt; i++) { 387cf890fe8SJonathan Cameron ret = __ad7280_read32(st, &tmp); 388cf890fe8SJonathan Cameron if (ret) 389cf890fe8SJonathan Cameron return ret; 390cf890fe8SJonathan Cameron 391cf890fe8SJonathan Cameron if (ad7280_check_crc(st, tmp)) 392cf890fe8SJonathan Cameron return -EIO; 393cf890fe8SJonathan Cameron 394cf890fe8SJonathan Cameron if (array) 395cf890fe8SJonathan Cameron array[i] = tmp; 396cf890fe8SJonathan Cameron /* only sum cell voltages */ 397cf890fe8SJonathan Cameron if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, tmp) <= 398cf890fe8SJonathan Cameron AD7280A_CELL_VOLTAGE_6_REG) 399cf890fe8SJonathan Cameron sum += FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, tmp); 400cf890fe8SJonathan Cameron } 401cf890fe8SJonathan Cameron 402cf890fe8SJonathan Cameron return sum; 403cf890fe8SJonathan Cameron } 404cf890fe8SJonathan Cameron 405cf890fe8SJonathan Cameron static void ad7280_sw_power_down(void *data) 406cf890fe8SJonathan Cameron { 407cf890fe8SJonathan Cameron struct ad7280_state *st = data; 408cf890fe8SJonathan Cameron 409cf890fe8SJonathan Cameron ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, 410cf890fe8SJonathan Cameron AD7280A_CTRL_HB_PWRDN_SW | 411cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); 412cf890fe8SJonathan Cameron } 413cf890fe8SJonathan Cameron 414cf890fe8SJonathan Cameron static int ad7280_chain_setup(struct ad7280_state *st) 415cf890fe8SJonathan Cameron { 416cf890fe8SJonathan Cameron unsigned int val, n; 417cf890fe8SJonathan Cameron int ret; 418cf890fe8SJonathan Cameron 419cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, 420cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | 421cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | 422cf890fe8SJonathan Cameron AD7280A_CTRL_LB_MUST_SET | 423cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 1) | 424cf890fe8SJonathan Cameron st->ctrl_lb); 425cf890fe8SJonathan Cameron if (ret) 426cf890fe8SJonathan Cameron return ret; 427cf890fe8SJonathan Cameron 428cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_LB_REG, 1, 429cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_DAISY_CHAIN_RB_MSK, 1) | 430cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_LOCK_DEV_ADDR_MSK, 1) | 431cf890fe8SJonathan Cameron AD7280A_CTRL_LB_MUST_SET | 432cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_SWRST_MSK, 0) | 433cf890fe8SJonathan Cameron st->ctrl_lb); 434cf890fe8SJonathan Cameron if (ret) 435cf890fe8SJonathan Cameron goto error_power_down; 436cf890fe8SJonathan Cameron 437cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ_REG, 1, 438cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_READ_ADDR_MSK, AD7280A_CTRL_LB_REG)); 439cf890fe8SJonathan Cameron if (ret) 440cf890fe8SJonathan Cameron goto error_power_down; 441cf890fe8SJonathan Cameron 442cf890fe8SJonathan Cameron for (n = 0; n <= AD7280A_MAX_CHAIN; n++) { 443cf890fe8SJonathan Cameron ret = __ad7280_read32(st, &val); 444cf890fe8SJonathan Cameron if (ret) 445cf890fe8SJonathan Cameron goto error_power_down; 446cf890fe8SJonathan Cameron 447cf890fe8SJonathan Cameron if (val == 0) 448cf890fe8SJonathan Cameron return n - 1; 449cf890fe8SJonathan Cameron 450cf890fe8SJonathan Cameron if (ad7280_check_crc(st, val)) { 451cf890fe8SJonathan Cameron ret = -EIO; 452cf890fe8SJonathan Cameron goto error_power_down; 453cf890fe8SJonathan Cameron } 454cf890fe8SJonathan Cameron 455cf890fe8SJonathan Cameron if (n != ad7280a_devaddr(FIELD_GET(AD7280A_TRANS_READ_DEVADDR_MSK, val))) { 456cf890fe8SJonathan Cameron ret = -EIO; 457cf890fe8SJonathan Cameron goto error_power_down; 458cf890fe8SJonathan Cameron } 459cf890fe8SJonathan Cameron } 460cf890fe8SJonathan Cameron ret = -EFAULT; 461cf890fe8SJonathan Cameron 462cf890fe8SJonathan Cameron error_power_down: 463cf890fe8SJonathan Cameron ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CTRL_HB_REG, 1, 464cf890fe8SJonathan Cameron AD7280A_CTRL_HB_PWRDN_SW | 465cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_HB_CONV_AVG_MSK, st->oversampling_ratio)); 466cf890fe8SJonathan Cameron 467cf890fe8SJonathan Cameron return ret; 468cf890fe8SJonathan Cameron } 469cf890fe8SJonathan Cameron 470cf890fe8SJonathan Cameron static ssize_t ad7280_show_balance_sw(struct iio_dev *indio_dev, 471cf890fe8SJonathan Cameron uintptr_t private, 472cf890fe8SJonathan Cameron const struct iio_chan_spec *chan, char *buf) 473cf890fe8SJonathan Cameron { 474cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 475cf890fe8SJonathan Cameron 476cf890fe8SJonathan Cameron return sysfs_emit(buf, "%d\n", 477cf890fe8SJonathan Cameron !!(st->cb_mask[chan->address >> 8] & 478cf890fe8SJonathan Cameron BIT(chan->address & 0xFF))); 479cf890fe8SJonathan Cameron } 480cf890fe8SJonathan Cameron 481cf890fe8SJonathan Cameron static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, 482cf890fe8SJonathan Cameron uintptr_t private, 483cf890fe8SJonathan Cameron const struct iio_chan_spec *chan, 484cf890fe8SJonathan Cameron const char *buf, size_t len) 485cf890fe8SJonathan Cameron { 486cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 487cf890fe8SJonathan Cameron unsigned int devaddr, ch; 488cf890fe8SJonathan Cameron bool readin; 489cf890fe8SJonathan Cameron int ret; 490cf890fe8SJonathan Cameron 491cf890fe8SJonathan Cameron ret = strtobool(buf, &readin); 492cf890fe8SJonathan Cameron if (ret) 493cf890fe8SJonathan Cameron return ret; 494cf890fe8SJonathan Cameron 495cf890fe8SJonathan Cameron devaddr = chan->address >> 8; 496cf890fe8SJonathan Cameron ch = chan->address & 0xFF; 497cf890fe8SJonathan Cameron 498cf890fe8SJonathan Cameron mutex_lock(&st->lock); 499cf890fe8SJonathan Cameron if (readin) 500cf890fe8SJonathan Cameron st->cb_mask[devaddr] |= BIT(ch); 501cf890fe8SJonathan Cameron else 502cf890fe8SJonathan Cameron st->cb_mask[devaddr] &= ~BIT(ch); 503cf890fe8SJonathan Cameron 504cf890fe8SJonathan Cameron ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, 505cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK, 506cf890fe8SJonathan Cameron st->cb_mask[devaddr])); 507cf890fe8SJonathan Cameron mutex_unlock(&st->lock); 508cf890fe8SJonathan Cameron 509cf890fe8SJonathan Cameron return ret ? ret : len; 510cf890fe8SJonathan Cameron } 511cf890fe8SJonathan Cameron 512cf890fe8SJonathan Cameron static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, 513cf890fe8SJonathan Cameron uintptr_t private, 514cf890fe8SJonathan Cameron const struct iio_chan_spec *chan, 515cf890fe8SJonathan Cameron char *buf) 516cf890fe8SJonathan Cameron { 517cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 518cf890fe8SJonathan Cameron unsigned int msecs; 519cf890fe8SJonathan Cameron int ret; 520cf890fe8SJonathan Cameron 521cf890fe8SJonathan Cameron mutex_lock(&st->lock); 522cf890fe8SJonathan Cameron ret = ad7280_read_reg(st, chan->address >> 8, 523cf890fe8SJonathan Cameron (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG); 524cf890fe8SJonathan Cameron mutex_unlock(&st->lock); 525cf890fe8SJonathan Cameron 526cf890fe8SJonathan Cameron if (ret < 0) 527cf890fe8SJonathan Cameron return ret; 528cf890fe8SJonathan Cameron 529cf890fe8SJonathan Cameron msecs = FIELD_GET(AD7280A_CB_TIMER_VAL_MSK, ret) * 71500; 530cf890fe8SJonathan Cameron 531cf890fe8SJonathan Cameron return sysfs_emit(buf, "%u.%u\n", msecs / 1000, msecs % 1000); 532cf890fe8SJonathan Cameron } 533cf890fe8SJonathan Cameron 534cf890fe8SJonathan Cameron static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, 535cf890fe8SJonathan Cameron uintptr_t private, 536cf890fe8SJonathan Cameron const struct iio_chan_spec *chan, 537cf890fe8SJonathan Cameron const char *buf, size_t len) 538cf890fe8SJonathan Cameron { 539cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 540cf890fe8SJonathan Cameron int val, val2; 541cf890fe8SJonathan Cameron int ret; 542cf890fe8SJonathan Cameron 543cf890fe8SJonathan Cameron ret = iio_str_to_fixpoint(buf, 1000, &val, &val2); 544cf890fe8SJonathan Cameron if (ret) 545cf890fe8SJonathan Cameron return ret; 546cf890fe8SJonathan Cameron 547cf890fe8SJonathan Cameron val = val * 1000 + val2; 548cf890fe8SJonathan Cameron val /= 71500; 549cf890fe8SJonathan Cameron 550cf890fe8SJonathan Cameron if (val > 31) 551cf890fe8SJonathan Cameron return -EINVAL; 552cf890fe8SJonathan Cameron 553cf890fe8SJonathan Cameron mutex_lock(&st->lock); 554cf890fe8SJonathan Cameron ret = ad7280_write(st, chan->address >> 8, 555cf890fe8SJonathan Cameron (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0, 556cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); 557cf890fe8SJonathan Cameron mutex_unlock(&st->lock); 558cf890fe8SJonathan Cameron 559cf890fe8SJonathan Cameron return ret ? ret : len; 560cf890fe8SJonathan Cameron } 561cf890fe8SJonathan Cameron 562cf890fe8SJonathan Cameron static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = { 563cf890fe8SJonathan Cameron { 564cf890fe8SJonathan Cameron .name = "balance_switch_en", 565cf890fe8SJonathan Cameron .read = ad7280_show_balance_sw, 566cf890fe8SJonathan Cameron .write = ad7280_store_balance_sw, 567cf890fe8SJonathan Cameron .shared = IIO_SEPARATE, 568cf890fe8SJonathan Cameron }, { 569cf890fe8SJonathan Cameron .name = "balance_switch_timer", 570cf890fe8SJonathan Cameron .read = ad7280_show_balance_timer, 571cf890fe8SJonathan Cameron .write = ad7280_store_balance_timer, 572cf890fe8SJonathan Cameron .shared = IIO_SEPARATE, 573cf890fe8SJonathan Cameron }, 574cf890fe8SJonathan Cameron {} 575cf890fe8SJonathan Cameron }; 576cf890fe8SJonathan Cameron 577cf890fe8SJonathan Cameron static const struct iio_event_spec ad7280_events[] = { 578cf890fe8SJonathan Cameron { 579cf890fe8SJonathan Cameron .type = IIO_EV_TYPE_THRESH, 580cf890fe8SJonathan Cameron .dir = IIO_EV_DIR_RISING, 581cf890fe8SJonathan Cameron .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), 582cf890fe8SJonathan Cameron }, { 583cf890fe8SJonathan Cameron .type = IIO_EV_TYPE_THRESH, 584cf890fe8SJonathan Cameron .dir = IIO_EV_DIR_FALLING, 585cf890fe8SJonathan Cameron .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), 586cf890fe8SJonathan Cameron }, 587cf890fe8SJonathan Cameron }; 588cf890fe8SJonathan Cameron 589cf890fe8SJonathan Cameron static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i, 590cf890fe8SJonathan Cameron bool irq_present) 591cf890fe8SJonathan Cameron { 592cf890fe8SJonathan Cameron chan->type = IIO_VOLTAGE; 593cf890fe8SJonathan Cameron chan->differential = 1; 594cf890fe8SJonathan Cameron chan->channel = i; 595cf890fe8SJonathan Cameron chan->channel2 = chan->channel + 1; 596cf890fe8SJonathan Cameron if (irq_present) { 597cf890fe8SJonathan Cameron chan->event_spec = ad7280_events; 598cf890fe8SJonathan Cameron chan->num_event_specs = ARRAY_SIZE(ad7280_events); 599cf890fe8SJonathan Cameron } 600cf890fe8SJonathan Cameron chan->ext_info = ad7280_cell_ext_info; 601cf890fe8SJonathan Cameron } 602cf890fe8SJonathan Cameron 603cf890fe8SJonathan Cameron static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i, 604cf890fe8SJonathan Cameron bool irq_present) 605cf890fe8SJonathan Cameron { 606cf890fe8SJonathan Cameron chan->type = IIO_TEMP; 607cf890fe8SJonathan Cameron chan->channel = i; 608cf890fe8SJonathan Cameron if (irq_present) { 609cf890fe8SJonathan Cameron chan->event_spec = ad7280_events; 610cf890fe8SJonathan Cameron chan->num_event_specs = ARRAY_SIZE(ad7280_events); 611cf890fe8SJonathan Cameron } 612cf890fe8SJonathan Cameron } 613cf890fe8SJonathan Cameron 614cf890fe8SJonathan Cameron static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, 615cf890fe8SJonathan Cameron int cnt) 616cf890fe8SJonathan Cameron { 617cf890fe8SJonathan Cameron chan->indexed = 1; 618cf890fe8SJonathan Cameron chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); 619cf890fe8SJonathan Cameron chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); 620cf890fe8SJonathan Cameron chan->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); 621cf890fe8SJonathan Cameron chan->address = addr; 622cf890fe8SJonathan Cameron chan->scan_index = cnt; 623cf890fe8SJonathan Cameron chan->scan_type.sign = 'u'; 624cf890fe8SJonathan Cameron chan->scan_type.realbits = 12; 625cf890fe8SJonathan Cameron chan->scan_type.storagebits = 32; 626cf890fe8SJonathan Cameron } 627cf890fe8SJonathan Cameron 628cf890fe8SJonathan Cameron static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, 629cf890fe8SJonathan Cameron int cnt, int dev) 630cf890fe8SJonathan Cameron { 631cf890fe8SJonathan Cameron chan->type = IIO_VOLTAGE; 632cf890fe8SJonathan Cameron chan->differential = 1; 633cf890fe8SJonathan Cameron chan->channel = 0; 634cf890fe8SJonathan Cameron chan->channel2 = dev * AD7280A_CELLS_PER_DEV; 635cf890fe8SJonathan Cameron chan->address = AD7280A_ALL_CELLS; 636cf890fe8SJonathan Cameron chan->indexed = 1; 637cf890fe8SJonathan Cameron chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); 638cf890fe8SJonathan Cameron chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); 639cf890fe8SJonathan Cameron chan->scan_index = cnt; 640cf890fe8SJonathan Cameron chan->scan_type.sign = 'u'; 641cf890fe8SJonathan Cameron chan->scan_type.realbits = 32; 642cf890fe8SJonathan Cameron chan->scan_type.storagebits = 32; 643cf890fe8SJonathan Cameron } 644cf890fe8SJonathan Cameron 645cf890fe8SJonathan Cameron static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt, 646cf890fe8SJonathan Cameron bool irq_present) 647cf890fe8SJonathan Cameron { 648cf890fe8SJonathan Cameron int addr, ch, i; 649cf890fe8SJonathan Cameron struct iio_chan_spec *chan; 650cf890fe8SJonathan Cameron 651cf890fe8SJonathan Cameron for (ch = AD7280A_CELL_VOLTAGE_1_REG; ch <= AD7280A_AUX_ADC_6_REG; ch++) { 652cf890fe8SJonathan Cameron chan = &st->channels[*cnt]; 653cf890fe8SJonathan Cameron 654cf890fe8SJonathan Cameron if (ch < AD7280A_AUX_ADC_1_REG) { 655cf890fe8SJonathan Cameron i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); 656cf890fe8SJonathan Cameron ad7280_voltage_channel_init(chan, i, irq_present); 657cf890fe8SJonathan Cameron } else { 658cf890fe8SJonathan Cameron i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch); 659cf890fe8SJonathan Cameron ad7280_temp_channel_init(chan, i, irq_present); 660cf890fe8SJonathan Cameron } 661cf890fe8SJonathan Cameron 662cf890fe8SJonathan Cameron addr = ad7280a_devaddr(dev) << 8 | ch; 663cf890fe8SJonathan Cameron ad7280_common_fields_init(chan, addr, *cnt); 664cf890fe8SJonathan Cameron 665cf890fe8SJonathan Cameron (*cnt)++; 666cf890fe8SJonathan Cameron } 667cf890fe8SJonathan Cameron } 668cf890fe8SJonathan Cameron 669cf890fe8SJonathan Cameron static int ad7280_channel_init(struct ad7280_state *st, bool irq_present) 670cf890fe8SJonathan Cameron { 671cf890fe8SJonathan Cameron int dev, cnt = 0; 672cf890fe8SJonathan Cameron 673cf890fe8SJonathan Cameron st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 1, 674cf890fe8SJonathan Cameron sizeof(*st->channels), GFP_KERNEL); 675cf890fe8SJonathan Cameron if (!st->channels) 676cf890fe8SJonathan Cameron return -ENOMEM; 677cf890fe8SJonathan Cameron 678cf890fe8SJonathan Cameron for (dev = 0; dev <= st->slave_num; dev++) 679cf890fe8SJonathan Cameron ad7280_init_dev_channels(st, dev, &cnt, irq_present); 680cf890fe8SJonathan Cameron 681cf890fe8SJonathan Cameron ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); 682cf890fe8SJonathan Cameron 683cf890fe8SJonathan Cameron return cnt + 1; 684cf890fe8SJonathan Cameron } 685cf890fe8SJonathan Cameron 686cf890fe8SJonathan Cameron static int ad7280a_read_thresh(struct iio_dev *indio_dev, 687cf890fe8SJonathan Cameron const struct iio_chan_spec *chan, 688cf890fe8SJonathan Cameron enum iio_event_type type, 689cf890fe8SJonathan Cameron enum iio_event_direction dir, 690cf890fe8SJonathan Cameron enum iio_event_info info, int *val, int *val2) 691cf890fe8SJonathan Cameron { 692cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 693cf890fe8SJonathan Cameron 694cf890fe8SJonathan Cameron switch (chan->type) { 695cf890fe8SJonathan Cameron case IIO_VOLTAGE: 696cf890fe8SJonathan Cameron switch (dir) { 697cf890fe8SJonathan Cameron case IIO_EV_DIR_RISING: 698cf890fe8SJonathan Cameron *val = 1000 + (st->cell_threshhigh * 1568L) / 100; 699cf890fe8SJonathan Cameron return IIO_VAL_INT; 700cf890fe8SJonathan Cameron case IIO_EV_DIR_FALLING: 701cf890fe8SJonathan Cameron *val = 1000 + (st->cell_threshlow * 1568L) / 100; 702cf890fe8SJonathan Cameron return IIO_VAL_INT; 703cf890fe8SJonathan Cameron default: 704cf890fe8SJonathan Cameron return -EINVAL; 705cf890fe8SJonathan Cameron } 706cf890fe8SJonathan Cameron break; 707cf890fe8SJonathan Cameron case IIO_TEMP: 708cf890fe8SJonathan Cameron switch (dir) { 709cf890fe8SJonathan Cameron case IIO_EV_DIR_RISING: 710cf890fe8SJonathan Cameron *val = ((st->aux_threshhigh) * 196L) / 10; 711cf890fe8SJonathan Cameron return IIO_VAL_INT; 712cf890fe8SJonathan Cameron case IIO_EV_DIR_FALLING: 713cf890fe8SJonathan Cameron *val = (st->aux_threshlow * 196L) / 10; 714cf890fe8SJonathan Cameron return IIO_VAL_INT; 715cf890fe8SJonathan Cameron default: 716cf890fe8SJonathan Cameron return -EINVAL; 717cf890fe8SJonathan Cameron } 718cf890fe8SJonathan Cameron break; 719cf890fe8SJonathan Cameron default: 720cf890fe8SJonathan Cameron return -EINVAL; 721cf890fe8SJonathan Cameron } 722cf890fe8SJonathan Cameron } 723cf890fe8SJonathan Cameron 724cf890fe8SJonathan Cameron static int ad7280a_write_thresh(struct iio_dev *indio_dev, 725cf890fe8SJonathan Cameron const struct iio_chan_spec *chan, 726cf890fe8SJonathan Cameron enum iio_event_type type, 727cf890fe8SJonathan Cameron enum iio_event_direction dir, 728cf890fe8SJonathan Cameron enum iio_event_info info, 729cf890fe8SJonathan Cameron int val, int val2) 730cf890fe8SJonathan Cameron { 731cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 732cf890fe8SJonathan Cameron unsigned int addr; 733cf890fe8SJonathan Cameron long value; 734cf890fe8SJonathan Cameron int ret; 735cf890fe8SJonathan Cameron 736cf890fe8SJonathan Cameron if (val2 != 0) 737cf890fe8SJonathan Cameron return -EINVAL; 738cf890fe8SJonathan Cameron 739cf890fe8SJonathan Cameron mutex_lock(&st->lock); 740cf890fe8SJonathan Cameron switch (chan->type) { 741cf890fe8SJonathan Cameron case IIO_VOLTAGE: 742cf890fe8SJonathan Cameron value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ 743cf890fe8SJonathan Cameron value = clamp(value, 0L, 0xFFL); 744cf890fe8SJonathan Cameron switch (dir) { 745cf890fe8SJonathan Cameron case IIO_EV_DIR_RISING: 746cf890fe8SJonathan Cameron addr = AD7280A_CELL_OVERVOLTAGE_REG; 747cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 748*03779df9SJonathan Cameron 1, value); 749cf890fe8SJonathan Cameron if (ret) 750cf890fe8SJonathan Cameron break; 751cf890fe8SJonathan Cameron st->cell_threshhigh = value; 752cf890fe8SJonathan Cameron break; 753cf890fe8SJonathan Cameron case IIO_EV_DIR_FALLING: 754cf890fe8SJonathan Cameron addr = AD7280A_CELL_UNDERVOLTAGE_REG; 755cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 756*03779df9SJonathan Cameron 1, value); 757cf890fe8SJonathan Cameron if (ret) 758cf890fe8SJonathan Cameron break; 759cf890fe8SJonathan Cameron st->cell_threshlow = value; 760cf890fe8SJonathan Cameron break; 761cf890fe8SJonathan Cameron default: 762cf890fe8SJonathan Cameron ret = -EINVAL; 763cf890fe8SJonathan Cameron goto err_unlock; 764cf890fe8SJonathan Cameron } 765cf890fe8SJonathan Cameron break; 766cf890fe8SJonathan Cameron case IIO_TEMP: 767cf890fe8SJonathan Cameron value = (val * 10) / 196; /* LSB 19.6mV */ 768cf890fe8SJonathan Cameron value = clamp(value, 0L, 0xFFL); 769cf890fe8SJonathan Cameron switch (dir) { 770cf890fe8SJonathan Cameron case IIO_EV_DIR_RISING: 771cf890fe8SJonathan Cameron addr = AD7280A_AUX_ADC_OVERVOLTAGE_REG; 772cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 773*03779df9SJonathan Cameron 1, value); 774cf890fe8SJonathan Cameron if (ret) 775cf890fe8SJonathan Cameron break; 776*03779df9SJonathan Cameron st->aux_threshhigh = value; 777cf890fe8SJonathan Cameron break; 778cf890fe8SJonathan Cameron case IIO_EV_DIR_FALLING: 779cf890fe8SJonathan Cameron addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG; 780cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 781*03779df9SJonathan Cameron 1, value); 782cf890fe8SJonathan Cameron if (ret) 783cf890fe8SJonathan Cameron break; 784*03779df9SJonathan Cameron st->aux_threshlow = value; 785cf890fe8SJonathan Cameron break; 786cf890fe8SJonathan Cameron default: 787cf890fe8SJonathan Cameron ret = -EINVAL; 788cf890fe8SJonathan Cameron goto err_unlock; 789cf890fe8SJonathan Cameron } 790cf890fe8SJonathan Cameron break; 791cf890fe8SJonathan Cameron default: 792cf890fe8SJonathan Cameron ret = -EINVAL; 793cf890fe8SJonathan Cameron goto err_unlock; 794cf890fe8SJonathan Cameron } 795cf890fe8SJonathan Cameron 796cf890fe8SJonathan Cameron err_unlock: 797cf890fe8SJonathan Cameron mutex_unlock(&st->lock); 798cf890fe8SJonathan Cameron 799cf890fe8SJonathan Cameron return ret; 800cf890fe8SJonathan Cameron } 801cf890fe8SJonathan Cameron 802cf890fe8SJonathan Cameron static irqreturn_t ad7280_event_handler(int irq, void *private) 803cf890fe8SJonathan Cameron { 804cf890fe8SJonathan Cameron struct iio_dev *indio_dev = private; 805cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 806cf890fe8SJonathan Cameron unsigned int *channels; 807cf890fe8SJonathan Cameron int i, ret; 808cf890fe8SJonathan Cameron 809cf890fe8SJonathan Cameron channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL); 810cf890fe8SJonathan Cameron if (!channels) 811cf890fe8SJonathan Cameron return IRQ_HANDLED; 812cf890fe8SJonathan Cameron 813cf890fe8SJonathan Cameron ret = ad7280_read_all_channels(st, st->scan_cnt, channels); 814cf890fe8SJonathan Cameron if (ret < 0) 815cf890fe8SJonathan Cameron goto out; 816cf890fe8SJonathan Cameron 817cf890fe8SJonathan Cameron for (i = 0; i < st->scan_cnt; i++) { 818cf890fe8SJonathan Cameron unsigned int val; 819cf890fe8SJonathan Cameron 820cf890fe8SJonathan Cameron val = FIELD_GET(AD7280A_TRANS_READ_CONV_DATA_MSK, channels[i]); 821cf890fe8SJonathan Cameron if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <= 822cf890fe8SJonathan Cameron AD7280A_CELL_VOLTAGE_6_REG) { 823cf890fe8SJonathan Cameron if (val >= st->cell_threshhigh) { 824cf890fe8SJonathan Cameron u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, 825cf890fe8SJonathan Cameron IIO_EV_DIR_RISING, 826cf890fe8SJonathan Cameron IIO_EV_TYPE_THRESH, 827cf890fe8SJonathan Cameron 0, 0, 0); 828cf890fe8SJonathan Cameron iio_push_event(indio_dev, tmp, 829cf890fe8SJonathan Cameron iio_get_time_ns(indio_dev)); 830cf890fe8SJonathan Cameron } else if (val <= st->cell_threshlow) { 831cf890fe8SJonathan Cameron u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, 832cf890fe8SJonathan Cameron IIO_EV_DIR_FALLING, 833cf890fe8SJonathan Cameron IIO_EV_TYPE_THRESH, 834cf890fe8SJonathan Cameron 0, 0, 0); 835cf890fe8SJonathan Cameron iio_push_event(indio_dev, tmp, 836cf890fe8SJonathan Cameron iio_get_time_ns(indio_dev)); 837cf890fe8SJonathan Cameron } 838cf890fe8SJonathan Cameron } else { 839cf890fe8SJonathan Cameron if (val >= st->aux_threshhigh) { 840cf890fe8SJonathan Cameron u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, 841cf890fe8SJonathan Cameron IIO_EV_TYPE_THRESH, 842cf890fe8SJonathan Cameron IIO_EV_DIR_RISING); 843cf890fe8SJonathan Cameron iio_push_event(indio_dev, tmp, 844cf890fe8SJonathan Cameron iio_get_time_ns(indio_dev)); 845cf890fe8SJonathan Cameron } else if (val <= st->aux_threshlow) { 846cf890fe8SJonathan Cameron u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, 847cf890fe8SJonathan Cameron IIO_EV_TYPE_THRESH, 848cf890fe8SJonathan Cameron IIO_EV_DIR_FALLING); 849cf890fe8SJonathan Cameron iio_push_event(indio_dev, tmp, 850cf890fe8SJonathan Cameron iio_get_time_ns(indio_dev)); 851cf890fe8SJonathan Cameron } 852cf890fe8SJonathan Cameron } 853cf890fe8SJonathan Cameron } 854cf890fe8SJonathan Cameron 855cf890fe8SJonathan Cameron out: 856cf890fe8SJonathan Cameron kfree(channels); 857cf890fe8SJonathan Cameron 858cf890fe8SJonathan Cameron return IRQ_HANDLED; 859cf890fe8SJonathan Cameron } 860cf890fe8SJonathan Cameron 861cf890fe8SJonathan Cameron static void ad7280_update_delay(struct ad7280_state *st) 862cf890fe8SJonathan Cameron { 863cf890fe8SJonathan Cameron /* 864cf890fe8SJonathan Cameron * Total Conversion Time = ((tACQ + tCONV) * 865cf890fe8SJonathan Cameron * (Number of Conversions per Part)) − 866cf890fe8SJonathan Cameron * tACQ + ((N - 1) * tDELAY) 867cf890fe8SJonathan Cameron * 868cf890fe8SJonathan Cameron * Readback Delay = Total Conversion Time + tWAIT 869cf890fe8SJonathan Cameron */ 870cf890fe8SJonathan Cameron 871cf890fe8SJonathan Cameron st->readback_delay_us = 872cf890fe8SJonathan Cameron ((ad7280a_t_acq_ns[st->acquisition_time & 0x3] + 720) * 873cf890fe8SJonathan Cameron (AD7280A_NUM_CH * ad7280a_n_avg[st->oversampling_ratio & 0x3])) - 874cf890fe8SJonathan Cameron ad7280a_t_acq_ns[st->acquisition_time & 0x3] + st->slave_num * 250; 875cf890fe8SJonathan Cameron 876cf890fe8SJonathan Cameron /* Convert to usecs */ 877cf890fe8SJonathan Cameron st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); 878cf890fe8SJonathan Cameron st->readback_delay_us += 5; /* Add tWAIT */ 879cf890fe8SJonathan Cameron } 880cf890fe8SJonathan Cameron 881cf890fe8SJonathan Cameron static int ad7280_read_raw(struct iio_dev *indio_dev, 882cf890fe8SJonathan Cameron struct iio_chan_spec const *chan, 883cf890fe8SJonathan Cameron int *val, 884cf890fe8SJonathan Cameron int *val2, 885cf890fe8SJonathan Cameron long m) 886cf890fe8SJonathan Cameron { 887cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 888cf890fe8SJonathan Cameron int ret; 889cf890fe8SJonathan Cameron 890cf890fe8SJonathan Cameron switch (m) { 891cf890fe8SJonathan Cameron case IIO_CHAN_INFO_RAW: 892cf890fe8SJonathan Cameron mutex_lock(&st->lock); 893cf890fe8SJonathan Cameron if (chan->address == AD7280A_ALL_CELLS) 894cf890fe8SJonathan Cameron ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); 895cf890fe8SJonathan Cameron else 896cf890fe8SJonathan Cameron ret = ad7280_read_channel(st, chan->address >> 8, 897cf890fe8SJonathan Cameron chan->address & 0xFF); 898cf890fe8SJonathan Cameron mutex_unlock(&st->lock); 899cf890fe8SJonathan Cameron 900cf890fe8SJonathan Cameron if (ret < 0) 901cf890fe8SJonathan Cameron return ret; 902cf890fe8SJonathan Cameron 903cf890fe8SJonathan Cameron *val = ret; 904cf890fe8SJonathan Cameron 905cf890fe8SJonathan Cameron return IIO_VAL_INT; 906cf890fe8SJonathan Cameron case IIO_CHAN_INFO_SCALE: 907cf890fe8SJonathan Cameron if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG) 908cf890fe8SJonathan Cameron *val = 4000; 909cf890fe8SJonathan Cameron else 910cf890fe8SJonathan Cameron *val = 5000; 911cf890fe8SJonathan Cameron 912cf890fe8SJonathan Cameron *val2 = AD7280A_BITS; 913cf890fe8SJonathan Cameron return IIO_VAL_FRACTIONAL_LOG2; 914cf890fe8SJonathan Cameron case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 915cf890fe8SJonathan Cameron *val = ad7280a_n_avg[st->oversampling_ratio]; 916cf890fe8SJonathan Cameron return IIO_VAL_INT; 917cf890fe8SJonathan Cameron } 918cf890fe8SJonathan Cameron return -EINVAL; 919cf890fe8SJonathan Cameron } 920cf890fe8SJonathan Cameron 921cf890fe8SJonathan Cameron static int ad7280_write_raw(struct iio_dev *indio_dev, 922cf890fe8SJonathan Cameron struct iio_chan_spec const *chan, 923cf890fe8SJonathan Cameron int val, int val2, long mask) 924cf890fe8SJonathan Cameron { 925cf890fe8SJonathan Cameron struct ad7280_state *st = iio_priv(indio_dev); 926cf890fe8SJonathan Cameron int i; 927cf890fe8SJonathan Cameron 928cf890fe8SJonathan Cameron switch (mask) { 929cf890fe8SJonathan Cameron case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 930cf890fe8SJonathan Cameron if (val2 != 0) 931cf890fe8SJonathan Cameron return -EINVAL; 932cf890fe8SJonathan Cameron for (i = 0; i < ARRAY_SIZE(ad7280a_n_avg); i++) { 933cf890fe8SJonathan Cameron if (val == ad7280a_n_avg[i]) { 934cf890fe8SJonathan Cameron st->oversampling_ratio = i; 935cf890fe8SJonathan Cameron ad7280_update_delay(st); 936cf890fe8SJonathan Cameron return 0; 937cf890fe8SJonathan Cameron } 938cf890fe8SJonathan Cameron } 939cf890fe8SJonathan Cameron return -EINVAL; 940cf890fe8SJonathan Cameron default: 941cf890fe8SJonathan Cameron return -EINVAL; 942cf890fe8SJonathan Cameron } 943cf890fe8SJonathan Cameron } 944cf890fe8SJonathan Cameron 945cf890fe8SJonathan Cameron static const struct iio_info ad7280_info = { 946cf890fe8SJonathan Cameron .read_raw = ad7280_read_raw, 947cf890fe8SJonathan Cameron .write_raw = ad7280_write_raw, 948cf890fe8SJonathan Cameron .read_event_value = &ad7280a_read_thresh, 949cf890fe8SJonathan Cameron .write_event_value = &ad7280a_write_thresh, 950cf890fe8SJonathan Cameron }; 951cf890fe8SJonathan Cameron 952cf890fe8SJonathan Cameron static const struct iio_info ad7280_info_no_irq = { 953cf890fe8SJonathan Cameron .read_raw = ad7280_read_raw, 954cf890fe8SJonathan Cameron .write_raw = ad7280_write_raw, 955cf890fe8SJonathan Cameron }; 956cf890fe8SJonathan Cameron 957cf890fe8SJonathan Cameron static int ad7280_probe(struct spi_device *spi) 958cf890fe8SJonathan Cameron { 959cf890fe8SJonathan Cameron struct device *dev = &spi->dev; 960cf890fe8SJonathan Cameron struct ad7280_state *st; 961cf890fe8SJonathan Cameron int ret; 962cf890fe8SJonathan Cameron struct iio_dev *indio_dev; 963cf890fe8SJonathan Cameron 964cf890fe8SJonathan Cameron indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 965cf890fe8SJonathan Cameron if (!indio_dev) 966cf890fe8SJonathan Cameron return -ENOMEM; 967cf890fe8SJonathan Cameron 968cf890fe8SJonathan Cameron st = iio_priv(indio_dev); 969cf890fe8SJonathan Cameron spi_set_drvdata(spi, indio_dev); 970cf890fe8SJonathan Cameron st->spi = spi; 971cf890fe8SJonathan Cameron mutex_init(&st->lock); 972cf890fe8SJonathan Cameron 973cf890fe8SJonathan Cameron st->thermistor_term_en = 974cf890fe8SJonathan Cameron device_property_read_bool(dev, "adi,thermistor-termination"); 975cf890fe8SJonathan Cameron 976cf890fe8SJonathan Cameron if (device_property_present(dev, "adi,acquisition-time-ns")) { 977cf890fe8SJonathan Cameron u32 val; 978cf890fe8SJonathan Cameron 979cf890fe8SJonathan Cameron ret = device_property_read_u32(dev, "adi,acquisition-time-ns", &val); 980cf890fe8SJonathan Cameron if (ret) 981cf890fe8SJonathan Cameron return ret; 982cf890fe8SJonathan Cameron 983cf890fe8SJonathan Cameron switch (val) { 984cf890fe8SJonathan Cameron case 400: 985cf890fe8SJonathan Cameron st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; 986cf890fe8SJonathan Cameron break; 987cf890fe8SJonathan Cameron case 800: 988cf890fe8SJonathan Cameron st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_800ns; 989cf890fe8SJonathan Cameron break; 990cf890fe8SJonathan Cameron case 1200: 991cf890fe8SJonathan Cameron st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1200ns; 992cf890fe8SJonathan Cameron break; 993cf890fe8SJonathan Cameron case 1600: 994cf890fe8SJonathan Cameron st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns; 995cf890fe8SJonathan Cameron break; 996cf890fe8SJonathan Cameron default: 997cf890fe8SJonathan Cameron dev_err(dev, "Firmware provided acquisition time is invalid\n"); 998cf890fe8SJonathan Cameron return -EINVAL; 999cf890fe8SJonathan Cameron } 1000cf890fe8SJonathan Cameron } else { 1001cf890fe8SJonathan Cameron st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; 1002cf890fe8SJonathan Cameron } 1003cf890fe8SJonathan Cameron 1004cf890fe8SJonathan Cameron /* Alert masks are intended for when particular inputs are not wired up */ 1005cf890fe8SJonathan Cameron if (device_property_present(dev, "adi,voltage-alert-last-chan")) { 1006cf890fe8SJonathan Cameron u32 val; 1007cf890fe8SJonathan Cameron 1008cf890fe8SJonathan Cameron ret = device_property_read_u32(dev, "adi,voltage-alert-last-chan", &val); 1009cf890fe8SJonathan Cameron if (ret) 1010cf890fe8SJonathan Cameron return ret; 1011cf890fe8SJonathan Cameron 1012cf890fe8SJonathan Cameron switch (val) { 1013cf890fe8SJonathan Cameron case 3: 1014cf890fe8SJonathan Cameron st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN4_VIN5; 1015cf890fe8SJonathan Cameron break; 1016cf890fe8SJonathan Cameron case 4: 1017cf890fe8SJonathan Cameron st->chain_last_alert_ignore |= AD7280A_ALERT_REMOVE_VIN5; 1018cf890fe8SJonathan Cameron break; 1019cf890fe8SJonathan Cameron case 5: 1020cf890fe8SJonathan Cameron break; 1021cf890fe8SJonathan Cameron default: 1022cf890fe8SJonathan Cameron dev_err(dev, 1023cf890fe8SJonathan Cameron "Firmware provided last voltage alert channel invalid\n"); 1024cf890fe8SJonathan Cameron break; 1025cf890fe8SJonathan Cameron } 1026cf890fe8SJonathan Cameron } 1027cf890fe8SJonathan Cameron crc8_populate_msb(st->crc_tab, POLYNOM); 1028cf890fe8SJonathan Cameron 1029cf890fe8SJonathan Cameron st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ; 1030cf890fe8SJonathan Cameron st->spi->mode = SPI_MODE_1; 1031cf890fe8SJonathan Cameron spi_setup(st->spi); 1032cf890fe8SJonathan Cameron 1033cf890fe8SJonathan Cameron st->ctrl_lb = FIELD_PREP(AD7280A_CTRL_LB_ACQ_TIME_MSK, st->acquisition_time) | 1034cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_CTRL_LB_THERMISTOR_MSK, st->thermistor_term_en); 1035cf890fe8SJonathan Cameron st->oversampling_ratio = 0; /* No oversampling */ 1036cf890fe8SJonathan Cameron 1037cf890fe8SJonathan Cameron ret = ad7280_chain_setup(st); 1038cf890fe8SJonathan Cameron if (ret < 0) 1039cf890fe8SJonathan Cameron return ret; 1040cf890fe8SJonathan Cameron 1041cf890fe8SJonathan Cameron st->slave_num = ret; 1042cf890fe8SJonathan Cameron st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; 1043cf890fe8SJonathan Cameron st->cell_threshhigh = 0xFF; 1044cf890fe8SJonathan Cameron st->aux_threshhigh = 0xFF; 1045cf890fe8SJonathan Cameron 1046cf890fe8SJonathan Cameron ret = devm_add_action_or_reset(dev, ad7280_sw_power_down, st); 1047cf890fe8SJonathan Cameron if (ret) 1048cf890fe8SJonathan Cameron return ret; 1049cf890fe8SJonathan Cameron 1050cf890fe8SJonathan Cameron ad7280_update_delay(st); 1051cf890fe8SJonathan Cameron 1052cf890fe8SJonathan Cameron indio_dev->name = spi_get_device_id(spi)->name; 1053cf890fe8SJonathan Cameron indio_dev->modes = INDIO_DIRECT_MODE; 1054cf890fe8SJonathan Cameron 1055cf890fe8SJonathan Cameron ret = ad7280_channel_init(st, spi->irq > 0); 1056cf890fe8SJonathan Cameron if (ret < 0) 1057cf890fe8SJonathan Cameron return ret; 1058cf890fe8SJonathan Cameron 1059cf890fe8SJonathan Cameron indio_dev->num_channels = ret; 1060cf890fe8SJonathan Cameron indio_dev->channels = st->channels; 1061cf890fe8SJonathan Cameron if (spi->irq > 0) { 1062cf890fe8SJonathan Cameron ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, 1063cf890fe8SJonathan Cameron AD7280A_ALERT_REG, 1, 1064cf890fe8SJonathan Cameron AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN); 1065cf890fe8SJonathan Cameron if (ret) 1066cf890fe8SJonathan Cameron return ret; 1067cf890fe8SJonathan Cameron 1068cf890fe8SJonathan Cameron ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), 1069cf890fe8SJonathan Cameron AD7280A_ALERT_REG, 0, 1070cf890fe8SJonathan Cameron AD7280A_ALERT_GEN_STATIC_HIGH | 1071cf890fe8SJonathan Cameron FIELD_PREP(AD7280A_ALERT_REMOVE_MSK, 1072cf890fe8SJonathan Cameron st->chain_last_alert_ignore)); 1073cf890fe8SJonathan Cameron if (ret) 1074cf890fe8SJonathan Cameron return ret; 1075cf890fe8SJonathan Cameron 1076cf890fe8SJonathan Cameron ret = devm_request_threaded_irq(dev, spi->irq, 1077cf890fe8SJonathan Cameron NULL, 1078cf890fe8SJonathan Cameron ad7280_event_handler, 1079cf890fe8SJonathan Cameron IRQF_TRIGGER_FALLING | 1080cf890fe8SJonathan Cameron IRQF_ONESHOT, 1081cf890fe8SJonathan Cameron indio_dev->name, 1082cf890fe8SJonathan Cameron indio_dev); 1083cf890fe8SJonathan Cameron if (ret) 1084cf890fe8SJonathan Cameron return ret; 1085cf890fe8SJonathan Cameron 1086cf890fe8SJonathan Cameron indio_dev->info = &ad7280_info; 1087cf890fe8SJonathan Cameron } else { 1088cf890fe8SJonathan Cameron indio_dev->info = &ad7280_info_no_irq; 1089cf890fe8SJonathan Cameron } 1090cf890fe8SJonathan Cameron 1091cf890fe8SJonathan Cameron return devm_iio_device_register(dev, indio_dev); 1092cf890fe8SJonathan Cameron } 1093cf890fe8SJonathan Cameron 1094cf890fe8SJonathan Cameron static const struct spi_device_id ad7280_id[] = { 1095cf890fe8SJonathan Cameron {"ad7280a", 0}, 1096cf890fe8SJonathan Cameron {} 1097cf890fe8SJonathan Cameron }; 1098cf890fe8SJonathan Cameron MODULE_DEVICE_TABLE(spi, ad7280_id); 1099cf890fe8SJonathan Cameron 1100cf890fe8SJonathan Cameron static struct spi_driver ad7280_driver = { 1101cf890fe8SJonathan Cameron .driver = { 1102cf890fe8SJonathan Cameron .name = "ad7280", 1103cf890fe8SJonathan Cameron }, 1104cf890fe8SJonathan Cameron .probe = ad7280_probe, 1105cf890fe8SJonathan Cameron .id_table = ad7280_id, 1106cf890fe8SJonathan Cameron }; 1107cf890fe8SJonathan Cameron module_spi_driver(ad7280_driver); 1108cf890fe8SJonathan Cameron 1109cf890fe8SJonathan Cameron MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 1110cf890fe8SJonathan Cameron MODULE_DESCRIPTION("Analog Devices AD7280A"); 1111cf890fe8SJonathan Cameron MODULE_LICENSE("GPL v2"); 1112