staging: IIO: DAC: AD5446: Add power down support
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> Acked-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
bd51c0b078
Коммит
bbed4dc791
|
@ -48,6 +48,20 @@ static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
|
||||||
st->data.d24[2] = val & 0xFF;
|
st->data.d24[2] = val & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode)
|
||||||
|
{
|
||||||
|
st->data.d16 = cpu_to_be16(mode << 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode)
|
||||||
|
{
|
||||||
|
unsigned val = mode << 16;
|
||||||
|
|
||||||
|
st->data.d24[0] = (val >> 16) & 0xFF;
|
||||||
|
st->data.d24[1] = (val >> 8) & 0xFF;
|
||||||
|
st->data.d24[2] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t ad5446_write(struct device *dev,
|
static ssize_t ad5446_write(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
|
@ -68,6 +82,7 @@ static ssize_t ad5446_write(struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev_info->mlock);
|
mutex_lock(&dev_info->mlock);
|
||||||
|
st->cached_val = val;
|
||||||
st->chip_info->store_sample(st, val);
|
st->chip_info->store_sample(st, val);
|
||||||
ret = spi_sync(st->spi, &st->msg);
|
ret = spi_sync(st->spi, &st->msg);
|
||||||
mutex_unlock(&dev_info->mlock);
|
mutex_unlock(&dev_info->mlock);
|
||||||
|
@ -102,15 +117,119 @@ static ssize_t ad5446_show_name(struct device *dev,
|
||||||
}
|
}
|
||||||
static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0);
|
static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0);
|
||||||
|
|
||||||
|
static ssize_t ad5446_write_powerdown_mode(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
||||||
|
struct ad5446_state *st = dev_info->dev_data;
|
||||||
|
|
||||||
|
if (sysfs_streq(buf, "1kohm_to_gnd"))
|
||||||
|
st->pwr_down_mode = MODE_PWRDWN_1k;
|
||||||
|
else if (sysfs_streq(buf, "100kohm_to_gnd"))
|
||||||
|
st->pwr_down_mode = MODE_PWRDWN_100k;
|
||||||
|
else if (sysfs_streq(buf, "three_state"))
|
||||||
|
st->pwr_down_mode = MODE_PWRDWN_TRISTATE;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ad5446_read_powerdown_mode(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
||||||
|
struct ad5446_state *st = dev_info->dev_data;
|
||||||
|
|
||||||
|
char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ad5446_read_dac_powerdown(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
||||||
|
struct ad5446_state *st = dev_info->dev_data;
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", st->pwr_down);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ad5446_write_dac_powerdown(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
||||||
|
struct ad5446_state *st = dev_info->dev_data;
|
||||||
|
unsigned long readin;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = strict_strtol(buf, 10, &readin);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (readin > 1)
|
||||||
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&dev_info->mlock);
|
||||||
|
st->pwr_down = readin;
|
||||||
|
|
||||||
|
if (st->pwr_down)
|
||||||
|
st->chip_info->store_pwr_down(st, st->pwr_down_mode);
|
||||||
|
else
|
||||||
|
st->chip_info->store_sample(st, st->cached_val);
|
||||||
|
|
||||||
|
ret = spi_sync(st->spi, &st->msg);
|
||||||
|
mutex_unlock(&dev_info->mlock);
|
||||||
|
|
||||||
|
return ret ? ret : len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR,
|
||||||
|
ad5446_read_powerdown_mode,
|
||||||
|
ad5446_write_powerdown_mode, 0);
|
||||||
|
|
||||||
|
static IIO_CONST_ATTR(out_powerdown_mode_available,
|
||||||
|
"1kohm_to_gnd 100kohm_to_gnd three_state");
|
||||||
|
|
||||||
|
static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR,
|
||||||
|
ad5446_read_dac_powerdown,
|
||||||
|
ad5446_write_dac_powerdown, 0);
|
||||||
|
|
||||||
static struct attribute *ad5446_attributes[] = {
|
static struct attribute *ad5446_attributes[] = {
|
||||||
&iio_dev_attr_out0_raw.dev_attr.attr,
|
&iio_dev_attr_out0_raw.dev_attr.attr,
|
||||||
&iio_dev_attr_out_scale.dev_attr.attr,
|
&iio_dev_attr_out_scale.dev_attr.attr,
|
||||||
|
&iio_dev_attr_out0_powerdown.dev_attr.attr,
|
||||||
|
&iio_dev_attr_out_powerdown_mode.dev_attr.attr,
|
||||||
|
&iio_const_attr_out_powerdown_mode_available.dev_attr.attr,
|
||||||
&iio_dev_attr_name.dev_attr.attr,
|
&iio_dev_attr_name.dev_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static mode_t ad5446_attr_is_visible(struct kobject *kobj,
|
||||||
|
struct attribute *attr, int n)
|
||||||
|
{
|
||||||
|
struct device *dev = container_of(kobj, struct device, kobj);
|
||||||
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
||||||
|
struct ad5446_state *st = iio_dev_get_devdata(dev_info);
|
||||||
|
|
||||||
|
mode_t mode = attr->mode;
|
||||||
|
|
||||||
|
if (!st->chip_info->store_pwr_down &&
|
||||||
|
(attr == &iio_dev_attr_out0_powerdown.dev_attr.attr ||
|
||||||
|
attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr ||
|
||||||
|
attr ==
|
||||||
|
&iio_const_attr_out_powerdown_mode_available.dev_attr.attr))
|
||||||
|
mode = 0;
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct attribute_group ad5446_attribute_group = {
|
static const struct attribute_group ad5446_attribute_group = {
|
||||||
.attrs = ad5446_attributes,
|
.attrs = ad5446_attributes,
|
||||||
|
.is_visible = ad5446_attr_is_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
|
@ -156,6 +275,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.left_shift = 2,
|
.left_shift = 2,
|
||||||
.int_vref_mv = 2500,
|
.int_vref_mv = 2500,
|
||||||
.store_sample = ad5620_store_sample,
|
.store_sample = ad5620_store_sample,
|
||||||
|
.store_pwr_down = ad5620_store_pwr_down,
|
||||||
},
|
},
|
||||||
[ID_AD5620_1250] = {
|
[ID_AD5620_1250] = {
|
||||||
.bits = 12,
|
.bits = 12,
|
||||||
|
@ -163,6 +283,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.left_shift = 2,
|
.left_shift = 2,
|
||||||
.int_vref_mv = 1250,
|
.int_vref_mv = 1250,
|
||||||
.store_sample = ad5620_store_sample,
|
.store_sample = ad5620_store_sample,
|
||||||
|
.store_pwr_down = ad5620_store_pwr_down,
|
||||||
},
|
},
|
||||||
[ID_AD5640_2500] = {
|
[ID_AD5640_2500] = {
|
||||||
.bits = 14,
|
.bits = 14,
|
||||||
|
@ -170,6 +291,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.left_shift = 0,
|
.left_shift = 0,
|
||||||
.int_vref_mv = 2500,
|
.int_vref_mv = 2500,
|
||||||
.store_sample = ad5620_store_sample,
|
.store_sample = ad5620_store_sample,
|
||||||
|
.store_pwr_down = ad5620_store_pwr_down,
|
||||||
},
|
},
|
||||||
[ID_AD5640_1250] = {
|
[ID_AD5640_1250] = {
|
||||||
.bits = 14,
|
.bits = 14,
|
||||||
|
@ -177,6 +299,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.left_shift = 0,
|
.left_shift = 0,
|
||||||
.int_vref_mv = 1250,
|
.int_vref_mv = 1250,
|
||||||
.store_sample = ad5620_store_sample,
|
.store_sample = ad5620_store_sample,
|
||||||
|
.store_pwr_down = ad5620_store_pwr_down,
|
||||||
},
|
},
|
||||||
[ID_AD5660_2500] = {
|
[ID_AD5660_2500] = {
|
||||||
.bits = 16,
|
.bits = 16,
|
||||||
|
@ -184,6 +307,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.left_shift = 0,
|
.left_shift = 0,
|
||||||
.int_vref_mv = 2500,
|
.int_vref_mv = 2500,
|
||||||
.store_sample = ad5660_store_sample,
|
.store_sample = ad5660_store_sample,
|
||||||
|
.store_pwr_down = ad5660_store_pwr_down,
|
||||||
},
|
},
|
||||||
[ID_AD5660_1250] = {
|
[ID_AD5660_1250] = {
|
||||||
.bits = 16,
|
.bits = 16,
|
||||||
|
@ -191,6 +315,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.left_shift = 0,
|
.left_shift = 0,
|
||||||
.int_vref_mv = 1250,
|
.int_vref_mv = 1250,
|
||||||
.store_sample = ad5660_store_sample,
|
.store_sample = ad5660_store_sample,
|
||||||
|
.store_pwr_down = ad5660_store_pwr_down,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -243,20 +368,20 @@ static int __devinit ad5446_probe(struct spi_device *spi)
|
||||||
spi_message_add_tail(&st->xfer, &st->msg);
|
spi_message_add_tail(&st->xfer, &st->msg);
|
||||||
|
|
||||||
switch (spi_get_device_id(spi)->driver_data) {
|
switch (spi_get_device_id(spi)->driver_data) {
|
||||||
case ID_AD5620_2500:
|
case ID_AD5620_2500:
|
||||||
case ID_AD5620_1250:
|
case ID_AD5620_1250:
|
||||||
case ID_AD5640_2500:
|
case ID_AD5640_2500:
|
||||||
case ID_AD5640_1250:
|
case ID_AD5640_1250:
|
||||||
case ID_AD5660_2500:
|
case ID_AD5660_2500:
|
||||||
case ID_AD5660_1250:
|
case ID_AD5660_1250:
|
||||||
st->vref_mv = st->chip_info->int_vref_mv;
|
st->vref_mv = st->chip_info->int_vref_mv;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (voltage_uv)
|
if (voltage_uv)
|
||||||
st->vref_mv = voltage_uv / 1000;
|
st->vref_mv = voltage_uv / 1000;
|
||||||
else
|
else
|
||||||
dev_warn(&spi->dev,
|
dev_warn(&spi->dev,
|
||||||
"reference voltage unspecified\n");
|
"reference voltage unspecified\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = iio_device_register(st->indio_dev);
|
ret = iio_device_register(st->indio_dev);
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
|
|
||||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||||
|
|
||||||
|
#define MODE_PWRDWN_1k 0x1
|
||||||
|
#define MODE_PWRDWN_100k 0x2
|
||||||
|
#define MODE_PWRDWN_TRISTATE 0x3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ad5446_state - driver instance specific data
|
* struct ad5446_state - driver instance specific data
|
||||||
* @indio_dev: the industrial I/O device
|
* @indio_dev: the industrial I/O device
|
||||||
|
@ -47,6 +51,9 @@ struct ad5446_state {
|
||||||
struct regulator *reg;
|
struct regulator *reg;
|
||||||
struct work_struct poll_work;
|
struct work_struct poll_work;
|
||||||
unsigned short vref_mv;
|
unsigned short vref_mv;
|
||||||
|
unsigned cached_val;
|
||||||
|
unsigned pwr_down_mode;
|
||||||
|
unsigned pwr_down;
|
||||||
struct spi_transfer xfer;
|
struct spi_transfer xfer;
|
||||||
struct spi_message msg;
|
struct spi_message msg;
|
||||||
union {
|
union {
|
||||||
|
@ -62,14 +69,16 @@ struct ad5446_state {
|
||||||
* @left_shift: number of bits the datum must be shifted
|
* @left_shift: number of bits the datum must be shifted
|
||||||
* @int_vref_mv: AD5620/40/60: the internal reference voltage
|
* @int_vref_mv: AD5620/40/60: the internal reference voltage
|
||||||
* @store_sample: chip specific helper function to store the datum
|
* @store_sample: chip specific helper function to store the datum
|
||||||
|
* @store_sample: chip specific helper function to store the powerpown cmd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct ad5446_chip_info {
|
struct ad5446_chip_info {
|
||||||
u8 bits;
|
u8 bits;
|
||||||
u8 storagebits;
|
u8 storagebits;
|
||||||
u8 left_shift;
|
u8 left_shift;
|
||||||
u16 int_vref_mv;
|
u16 int_vref_mv;
|
||||||
void (*store_sample) (struct ad5446_state *st, unsigned val);
|
void (*store_sample) (struct ad5446_state *st, unsigned val);
|
||||||
|
void (*store_pwr_down) (struct ad5446_state *st, unsigned mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче