Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}