diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2011-03-10 07:26:47 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-03-14 14:50:28 -0400 |
commit | bbed4dc791036e97cbe844935dece153fdace0dc (patch) | |
tree | 15a79b283066f4b324cfee1f36b17a22b810dda3 /drivers/staging | |
parent | bd51c0b078eb3edeee9e48eb236d5831d7ae34cf (diff) |
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>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/iio/dac/ad5446.c | 153 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5446.h | 19 |
2 files changed, 153 insertions, 19 deletions
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index 4f1d8813272..861a7eacdaf 100644 --- a/drivers/staging/iio/dac/ad5446.c +++ b/drivers/staging/iio/dac/ad5446.c | |||
@@ -48,6 +48,20 @@ static void ad5660_store_sample(struct ad5446_state *st, unsigned val) | |||
48 | st->data.d24[2] = val & 0xFF; | 48 | st->data.d24[2] = val & 0xFF; |
49 | } | 49 | } |
50 | 50 | ||
51 | static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode) | ||
52 | { | ||
53 | st->data.d16 = cpu_to_be16(mode << 14); | ||
54 | } | ||
55 | |||
56 | static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode) | ||
57 | { | ||
58 | unsigned val = mode << 16; | ||
59 | |||
60 | st->data.d24[0] = (val >> 16) & 0xFF; | ||
61 | st->data.d24[1] = (val >> 8) & 0xFF; | ||
62 | st->data.d24[2] = val & 0xFF; | ||
63 | } | ||
64 | |||
51 | static ssize_t ad5446_write(struct device *dev, | 65 | static ssize_t ad5446_write(struct device *dev, |
52 | struct device_attribute *attr, | 66 | struct device_attribute *attr, |
53 | const char *buf, | 67 | const char *buf, |
@@ -68,6 +82,7 @@ static ssize_t ad5446_write(struct device *dev, | |||
68 | } | 82 | } |
69 | 83 | ||
70 | mutex_lock(&dev_info->mlock); | 84 | mutex_lock(&dev_info->mlock); |
85 | st->cached_val = val; | ||
71 | st->chip_info->store_sample(st, val); | 86 | st->chip_info->store_sample(st, val); |
72 | ret = spi_sync(st->spi, &st->msg); | 87 | ret = spi_sync(st->spi, &st->msg); |
73 | mutex_unlock(&dev_info->mlock); | 88 | mutex_unlock(&dev_info->mlock); |
@@ -102,15 +117,119 @@ static ssize_t ad5446_show_name(struct device *dev, | |||
102 | } | 117 | } |
103 | static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0); | 118 | static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0); |
104 | 119 | ||
120 | static ssize_t ad5446_write_powerdown_mode(struct device *dev, | ||
121 | struct device_attribute *attr, | ||
122 | const char *buf, size_t len) | ||
123 | { | ||
124 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
125 | struct ad5446_state *st = dev_info->dev_data; | ||
126 | |||
127 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
128 | st->pwr_down_mode = MODE_PWRDWN_1k; | ||
129 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
130 | st->pwr_down_mode = MODE_PWRDWN_100k; | ||
131 | else if (sysfs_streq(buf, "three_state")) | ||
132 | st->pwr_down_mode = MODE_PWRDWN_TRISTATE; | ||
133 | else | ||
134 | return -EINVAL; | ||
135 | |||
136 | return len; | ||
137 | } | ||
138 | |||
139 | static ssize_t ad5446_read_powerdown_mode(struct device *dev, | ||
140 | struct device_attribute *attr, char *buf) | ||
141 | { | ||
142 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
143 | struct ad5446_state *st = dev_info->dev_data; | ||
144 | |||
145 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
146 | |||
147 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
148 | } | ||
149 | |||
150 | static ssize_t ad5446_read_dac_powerdown(struct device *dev, | ||
151 | struct device_attribute *attr, | ||
152 | char *buf) | ||
153 | { | ||
154 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
155 | struct ad5446_state *st = dev_info->dev_data; | ||
156 | |||
157 | return sprintf(buf, "%d\n", st->pwr_down); | ||
158 | } | ||
159 | |||
160 | static ssize_t ad5446_write_dac_powerdown(struct device *dev, | ||
161 | struct device_attribute *attr, | ||
162 | const char *buf, size_t len) | ||
163 | { | ||
164 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
165 | struct ad5446_state *st = dev_info->dev_data; | ||
166 | unsigned long readin; | ||
167 | int ret; | ||
168 | |||
169 | ret = strict_strtol(buf, 10, &readin); | ||
170 | if (ret) | ||
171 | return ret; | ||
172 | |||
173 | if (readin > 1) | ||
174 | ret = -EINVAL; | ||
175 | |||
176 | mutex_lock(&dev_info->mlock); | ||
177 | st->pwr_down = readin; | ||
178 | |||
179 | if (st->pwr_down) | ||
180 | st->chip_info->store_pwr_down(st, st->pwr_down_mode); | ||
181 | else | ||
182 | st->chip_info->store_sample(st, st->cached_val); | ||
183 | |||
184 | ret = spi_sync(st->spi, &st->msg); | ||
185 | mutex_unlock(&dev_info->mlock); | ||
186 | |||
187 | return ret ? ret : len; | ||
188 | } | ||
189 | |||
190 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR, | ||
191 | ad5446_read_powerdown_mode, | ||
192 | ad5446_write_powerdown_mode, 0); | ||
193 | |||
194 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
195 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
196 | |||
197 | static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR, | ||
198 | ad5446_read_dac_powerdown, | ||
199 | ad5446_write_dac_powerdown, 0); | ||
200 | |||
105 | static struct attribute *ad5446_attributes[] = { | 201 | static struct attribute *ad5446_attributes[] = { |
106 | &iio_dev_attr_out0_raw.dev_attr.attr, | 202 | &iio_dev_attr_out0_raw.dev_attr.attr, |
107 | &iio_dev_attr_out_scale.dev_attr.attr, | 203 | &iio_dev_attr_out_scale.dev_attr.attr, |
204 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
205 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
206 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
108 | &iio_dev_attr_name.dev_attr.attr, | 207 | &iio_dev_attr_name.dev_attr.attr, |
109 | NULL, | 208 | NULL, |
110 | }; | 209 | }; |
111 | 210 | ||
211 | static mode_t ad5446_attr_is_visible(struct kobject *kobj, | ||
212 | struct attribute *attr, int n) | ||
213 | { | ||
214 | struct device *dev = container_of(kobj, struct device, kobj); | ||
215 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
216 | struct ad5446_state *st = iio_dev_get_devdata(dev_info); | ||
217 | |||
218 | mode_t mode = attr->mode; | ||
219 | |||
220 | if (!st->chip_info->store_pwr_down && | ||
221 | (attr == &iio_dev_attr_out0_powerdown.dev_attr.attr || | ||
222 | attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr || | ||
223 | attr == | ||
224 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr)) | ||
225 | mode = 0; | ||
226 | |||
227 | return mode; | ||
228 | } | ||
229 | |||
112 | static const struct attribute_group ad5446_attribute_group = { | 230 | static const struct attribute_group ad5446_attribute_group = { |
113 | .attrs = ad5446_attributes, | 231 | .attrs = ad5446_attributes, |
232 | .is_visible = ad5446_attr_is_visible, | ||
114 | }; | 233 | }; |
115 | 234 | ||
116 | static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | 235 | static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { |
@@ -156,6 +275,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | |||
156 | .left_shift = 2, | 275 | .left_shift = 2, |
157 | .int_vref_mv = 2500, | 276 | .int_vref_mv = 2500, |
158 | .store_sample = ad5620_store_sample, | 277 | .store_sample = ad5620_store_sample, |
278 | .store_pwr_down = ad5620_store_pwr_down, | ||
159 | }, | 279 | }, |
160 | [ID_AD5620_1250] = { | 280 | [ID_AD5620_1250] = { |
161 | .bits = 12, | 281 | .bits = 12, |
@@ -163,6 +283,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | |||
163 | .left_shift = 2, | 283 | .left_shift = 2, |
164 | .int_vref_mv = 1250, | 284 | .int_vref_mv = 1250, |
165 | .store_sample = ad5620_store_sample, | 285 | .store_sample = ad5620_store_sample, |
286 | .store_pwr_down = ad5620_store_pwr_down, | ||
166 | }, | 287 | }, |
167 | [ID_AD5640_2500] = { | 288 | [ID_AD5640_2500] = { |
168 | .bits = 14, | 289 | .bits = 14, |
@@ -170,6 +291,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | |||
170 | .left_shift = 0, | 291 | .left_shift = 0, |
171 | .int_vref_mv = 2500, | 292 | .int_vref_mv = 2500, |
172 | .store_sample = ad5620_store_sample, | 293 | .store_sample = ad5620_store_sample, |
294 | .store_pwr_down = ad5620_store_pwr_down, | ||
173 | }, | 295 | }, |
174 | [ID_AD5640_1250] = { | 296 | [ID_AD5640_1250] = { |
175 | .bits = 14, | 297 | .bits = 14, |
@@ -177,6 +299,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | |||
177 | .left_shift = 0, | 299 | .left_shift = 0, |
178 | .int_vref_mv = 1250, | 300 | .int_vref_mv = 1250, |
179 | .store_sample = ad5620_store_sample, | 301 | .store_sample = ad5620_store_sample, |
302 | .store_pwr_down = ad5620_store_pwr_down, | ||
180 | }, | 303 | }, |
181 | [ID_AD5660_2500] = { | 304 | [ID_AD5660_2500] = { |
182 | .bits = 16, | 305 | .bits = 16, |
@@ -184,6 +307,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | |||
184 | .left_shift = 0, | 307 | .left_shift = 0, |
185 | .int_vref_mv = 2500, | 308 | .int_vref_mv = 2500, |
186 | .store_sample = ad5660_store_sample, | 309 | .store_sample = ad5660_store_sample, |
310 | .store_pwr_down = ad5660_store_pwr_down, | ||
187 | }, | 311 | }, |
188 | [ID_AD5660_1250] = { | 312 | [ID_AD5660_1250] = { |
189 | .bits = 16, | 313 | .bits = 16, |
@@ -191,6 +315,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | |||
191 | .left_shift = 0, | 315 | .left_shift = 0, |
192 | .int_vref_mv = 1250, | 316 | .int_vref_mv = 1250, |
193 | .store_sample = ad5660_store_sample, | 317 | .store_sample = ad5660_store_sample, |
318 | .store_pwr_down = ad5660_store_pwr_down, | ||
194 | }, | 319 | }, |
195 | }; | 320 | }; |
196 | 321 | ||
@@ -243,20 +368,20 @@ static int __devinit ad5446_probe(struct spi_device *spi) | |||
243 | spi_message_add_tail(&st->xfer, &st->msg); | 368 | spi_message_add_tail(&st->xfer, &st->msg); |
244 | 369 | ||
245 | switch (spi_get_device_id(spi)->driver_data) { | 370 | switch (spi_get_device_id(spi)->driver_data) { |
246 | case ID_AD5620_2500: | 371 | case ID_AD5620_2500: |
247 | case ID_AD5620_1250: | 372 | case ID_AD5620_1250: |
248 | case ID_AD5640_2500: | 373 | case ID_AD5640_2500: |
249 | case ID_AD5640_1250: | 374 | case ID_AD5640_1250: |
250 | case ID_AD5660_2500: | 375 | case ID_AD5660_2500: |
251 | case ID_AD5660_1250: | 376 | case ID_AD5660_1250: |
252 | st->vref_mv = st->chip_info->int_vref_mv; | 377 | st->vref_mv = st->chip_info->int_vref_mv; |
253 | break; | 378 | break; |
254 | default: | 379 | default: |
255 | if (voltage_uv) | 380 | if (voltage_uv) |
256 | st->vref_mv = voltage_uv / 1000; | 381 | st->vref_mv = voltage_uv / 1000; |
257 | else | 382 | else |
258 | dev_warn(&spi->dev, | 383 | dev_warn(&spi->dev, |
259 | "reference voltage unspecified\n"); | 384 | "reference voltage unspecified\n"); |
260 | } | 385 | } |
261 | 386 | ||
262 | ret = iio_device_register(st->indio_dev); | 387 | ret = iio_device_register(st->indio_dev); |
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h index 0cb9c14279e..e9397a6783c 100644 --- a/drivers/staging/iio/dac/ad5446.h +++ b/drivers/staging/iio/dac/ad5446.h | |||
@@ -27,6 +27,10 @@ | |||
27 | 27 | ||
28 | #define RES_MASK(bits) ((1 << (bits)) - 1) | 28 | #define RES_MASK(bits) ((1 << (bits)) - 1) |
29 | 29 | ||
30 | #define MODE_PWRDWN_1k 0x1 | ||
31 | #define MODE_PWRDWN_100k 0x2 | ||
32 | #define MODE_PWRDWN_TRISTATE 0x3 | ||
33 | |||
30 | /** | 34 | /** |
31 | * struct ad5446_state - driver instance specific data | 35 | * struct ad5446_state - driver instance specific data |
32 | * @indio_dev: the industrial I/O device | 36 | * @indio_dev: the industrial I/O device |
@@ -47,6 +51,9 @@ struct ad5446_state { | |||
47 | struct regulator *reg; | 51 | struct regulator *reg; |
48 | struct work_struct poll_work; | 52 | struct work_struct poll_work; |
49 | unsigned short vref_mv; | 53 | unsigned short vref_mv; |
54 | unsigned cached_val; | ||
55 | unsigned pwr_down_mode; | ||
56 | unsigned pwr_down; | ||
50 | struct spi_transfer xfer; | 57 | struct spi_transfer xfer; |
51 | struct spi_message msg; | 58 | struct spi_message msg; |
52 | union { | 59 | union { |
@@ -62,14 +69,16 @@ struct ad5446_state { | |||
62 | * @left_shift: number of bits the datum must be shifted | 69 | * @left_shift: number of bits the datum must be shifted |
63 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | 70 | * @int_vref_mv: AD5620/40/60: the internal reference voltage |
64 | * @store_sample: chip specific helper function to store the datum | 71 | * @store_sample: chip specific helper function to store the datum |
72 | * @store_sample: chip specific helper function to store the powerpown cmd | ||
65 | */ | 73 | */ |
66 | 74 | ||
67 | struct ad5446_chip_info { | 75 | struct ad5446_chip_info { |
68 | u8 bits; | 76 | u8 bits; |
69 | u8 storagebits; | 77 | u8 storagebits; |
70 | u8 left_shift; | 78 | u8 left_shift; |
71 | u16 int_vref_mv; | 79 | u16 int_vref_mv; |
72 | void (*store_sample) (struct ad5446_state *st, unsigned val); | 80 | void (*store_sample) (struct ad5446_state *st, unsigned val); |
81 | void (*store_pwr_down) (struct ad5446_state *st, unsigned mode); | ||
73 | }; | 82 | }; |
74 | 83 | ||
75 | /** | 84 | /** |