static int ad5504_spi_read(struct ad5504_state *st, u8 addr) { int ret; struct spi_transfer t = { .tx_buf = &st->data[0], .rx_buf = &st->data[1], .len = 2, }; st->data[0] = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); ret = spi_sync_transfer(st->spi, &t, 1); if (ret < 0) return ret; return be16_to_cpu(st->data[1]) & AD5504_RES_MASK; } static int ad5504_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m) { struct ad5504_state *st = iio_priv(indio_dev); int ret; switch (m) { case IIO_CHAN_INFO_RAW: ret = ad5504_spi_read(st, chan->address); if (ret < 0) return ret; *val = ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = st->vref_mv; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } static int ad5504_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct ad5504_state *st = iio_priv(indio_dev); switch (mask) { case IIO_CHAN_INFO_RAW: if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; return ad5504_spi_write(st, chan->address, val); default: return -EINVAL; } } static const char * const ad5504_powerdown_modes[] = { "20kohm_to_gnd", "three_state", }; static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { struct ad5504_state *st = iio_priv(indio_dev); return st->pwr_down_mode; } static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int mode) { struct ad5504_state *st = iio_priv(indio_dev); st->pwr_down_mode = mode; return 0; } static const struct iio_enum ad5504_powerdown_mode_enum = { .items = ad5504_powerdown_modes, .num_items = ARRAY_SIZE(ad5504_powerdown_modes), .get = ad5504_get_powerdown_mode, .set = ad5504_set_powerdown_mode, }; static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad5504_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", !(st->pwr_down_mask & (1 << chan->channel))); } static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, const char *buf, size_t len) { bool pwr_down; int ret; struct ad5504_state *st = iio_priv(indio_dev); ret = strtobool(buf, &pwr_down); if (ret) return ret; if (pwr_down) st->pwr_down_mask |= (1 << chan->channel); else st->pwr_down_mask &= ~(1 << chan->channel); ret = ad5504_spi_write(st, AD5504_ADDR_CTRL, AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) | AD5504_DAC_PWR(st->pwr_down_mask)); /* writes to the CTRL register must be followed by a NOOP */ ad5504_spi_write(st, AD5504_ADDR_NOOP, 0); return ret ? ret : len; } static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000"); static IIO_CONST_ATTR(temp0_thresh_rising_en, "1"); static struct attribute *ad5504_ev_attributes[] = { &iio_const_attr_temp0_thresh_rising_value.dev_attr.attr, &iio_const_attr_temp0_thresh_rising_en.dev_attr.attr, NULL, }; static struct attribute_group ad5504_ev_attribute_group = { .attrs = ad5504_ev_attributes, }; static irqreturn_t ad5504_event_handler(int irq, void *private) { iio_push_event(private, IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), iio_get_time_ns((struct iio_dev *)private)); return IRQ_HANDLED; }
static int ad5504_spi_read(struct spi_device *spi, u8 addr, u16 *val) { u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); int ret; struct spi_transfer t = { .tx_buf = &tmp, .rx_buf = val, .len = 2, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); ret = spi_sync(spi, &m); *val = be16_to_cpu(*val) & AD5504_RES_MASK; return ret; } static ssize_t ad5504_write_dac(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); long readin; int ret; ret = strict_strtol(buf, 10, &readin); if (ret) return ret; ret = ad5504_spi_write(st->spi, this_attr->address, readin); return ret ? ret : len; } static ssize_t ad5504_read_dac(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; u16 val; ret = ad5504_spi_read(st->spi, this_attr->address, &val); if (ret) return ret; return sprintf(buf, "%d\n", val); } static ssize_t ad5504_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); const char mode[][14] = {"20kohm_to_gnd", "three_state"}; return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); } static ssize_t ad5504_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); int ret; if (sysfs_streq(buf, "20kohm_to_gnd")) st->pwr_down_mode = AD5504_DAC_PWRDN_20K; else if (sysfs_streq(buf, "three_state")) st->pwr_down_mode = AD5504_DAC_PWRDN_3STATE; else ret = -EINVAL; return ret ? ret : len; } static ssize_t ad5504_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); return sprintf(buf, "%d\n", !(st->pwr_down_mask & (1 << this_attr->address))); } static ssize_t ad5504_write_dac_powerdown(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { long readin; int ret; struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); ret = strict_strtol(buf, 10, &readin); if (ret) return ret; if (readin == 0) st->pwr_down_mask |= (1 << this_attr->address); else if (readin == 1) st->pwr_down_mask &= ~(1 << this_attr->address); else ret = -EINVAL; ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL, AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) | AD5504_DAC_PWR(st->pwr_down_mask)); /* writes to the CTRL register must be followed by a NOOP */ ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0); return ret ? ret : len; }