]>
Commit | Line | Data |
---|---|---|
6ddc5fb4 RS |
1 | /* |
2 | * max517.c - Support for Maxim MAX517, MAX518 and MAX519 | |
3 | * | |
4 | * Copyright (C) 2010, 2011 Roland Stigge <[email protected]> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | ||
21 | #include <linux/module.h> | |
6ddc5fb4 RS |
22 | #include <linux/slab.h> |
23 | #include <linux/jiffies.h> | |
24 | #include <linux/i2c.h> | |
25 | #include <linux/err.h> | |
26 | ||
06458e27 JC |
27 | #include <linux/iio/iio.h> |
28 | #include <linux/iio/sysfs.h> | |
dbdc025b | 29 | #include <linux/iio/dac/max517.h> |
6ddc5fb4 RS |
30 | |
31 | #define MAX517_DRV_NAME "max517" | |
32 | ||
33 | /* Commands */ | |
34 | #define COMMAND_CHANNEL0 0x00 | |
35 | #define COMMAND_CHANNEL1 0x01 /* for MAX518 and MAX519 */ | |
36 | #define COMMAND_PD 0x08 /* Power Down */ | |
37 | ||
38 | enum max517_device_ids { | |
39 | ID_MAX517, | |
40 | ID_MAX518, | |
41 | ID_MAX519, | |
a878a1a6 AF |
42 | ID_MAX520, |
43 | ID_MAX521, | |
6ddc5fb4 RS |
44 | }; |
45 | ||
46 | struct max517_data { | |
826514b4 | 47 | struct i2c_client *client; |
a878a1a6 | 48 | unsigned short vref_mv[8]; |
6ddc5fb4 RS |
49 | }; |
50 | ||
51 | /* | |
52 | * channel: bit 0: channel 1 | |
53 | * bit 1: channel 2 | |
54 | * (this way, it's possible to set both channels at once) | |
55 | */ | |
4cd8d874 LPC |
56 | static int max517_set_value(struct iio_dev *indio_dev, |
57 | long val, int channel) | |
6ddc5fb4 | 58 | { |
638e59fc | 59 | struct max517_data *data = iio_priv(indio_dev); |
826514b4 | 60 | struct i2c_client *client = data->client; |
4cd8d874 | 61 | u8 outbuf[2]; |
6ddc5fb4 | 62 | int res; |
6ddc5fb4 RS |
63 | |
64 | if (val < 0 || val > 255) | |
65 | return -EINVAL; | |
66 | ||
4cd8d874 LPC |
67 | outbuf[0] = channel; |
68 | outbuf[1] = val; | |
6ddc5fb4 | 69 | |
4cd8d874 | 70 | res = i2c_master_send(client, outbuf, 2); |
6ddc5fb4 RS |
71 | if (res < 0) |
72 | return res; | |
4cd8d874 LPC |
73 | else if (res != 2) |
74 | return -EIO; | |
75 | else | |
76 | return 0; | |
6ddc5fb4 | 77 | } |
6ddc5fb4 | 78 | |
4cd8d874 LPC |
79 | static int max517_read_raw(struct iio_dev *indio_dev, |
80 | struct iio_chan_spec const *chan, | |
81 | int *val, | |
82 | int *val2, | |
83 | long m) | |
6ddc5fb4 | 84 | { |
638e59fc | 85 | struct max517_data *data = iio_priv(indio_dev); |
4cd8d874 LPC |
86 | |
87 | switch (m) { | |
88 | case IIO_CHAN_INFO_SCALE: | |
89 | /* Corresponds to Vref / 2^(bits) */ | |
998f129c LPC |
90 | *val = data->vref_mv[chan->channel]; |
91 | *val2 = 8; | |
92 | return IIO_VAL_FRACTIONAL_LOG2; | |
4cd8d874 LPC |
93 | default: |
94 | break; | |
95 | } | |
96 | return -EINVAL; | |
6ddc5fb4 RS |
97 | } |
98 | ||
4cd8d874 LPC |
99 | static int max517_write_raw(struct iio_dev *indio_dev, |
100 | struct iio_chan_spec const *chan, int val, int val2, long mask) | |
6ddc5fb4 | 101 | { |
4cd8d874 LPC |
102 | int ret; |
103 | ||
104 | switch (mask) { | |
105 | case IIO_CHAN_INFO_RAW: | |
106 | ret = max517_set_value(indio_dev, val, chan->channel); | |
107 | break; | |
108 | default: | |
109 | ret = -EINVAL; | |
110 | break; | |
111 | } | |
6ddc5fb4 | 112 | |
4cd8d874 | 113 | return ret; |
6ddc5fb4 | 114 | } |
6ddc5fb4 | 115 | |
fe8a5420 | 116 | static int __maybe_unused max517_suspend(struct device *dev) |
6ddc5fb4 RS |
117 | { |
118 | u8 outbuf = COMMAND_PD; | |
119 | ||
01788c53 | 120 | return i2c_master_send(to_i2c_client(dev), &outbuf, 1); |
6ddc5fb4 RS |
121 | } |
122 | ||
fe8a5420 | 123 | static int __maybe_unused max517_resume(struct device *dev) |
6ddc5fb4 RS |
124 | { |
125 | u8 outbuf = 0; | |
126 | ||
01788c53 | 127 | return i2c_master_send(to_i2c_client(dev), &outbuf, 1); |
6ddc5fb4 RS |
128 | } |
129 | ||
01788c53 | 130 | static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume); |
01788c53 | 131 | |
6fe8135f | 132 | static const struct iio_info max517_info = { |
4cd8d874 LPC |
133 | .read_raw = max517_read_raw, |
134 | .write_raw = max517_write_raw, | |
6fe8135f JC |
135 | }; |
136 | ||
4cd8d874 LPC |
137 | #define MAX517_CHANNEL(chan) { \ |
138 | .type = IIO_VOLTAGE, \ | |
139 | .indexed = 1, \ | |
140 | .output = 1, \ | |
141 | .channel = (chan), \ | |
040b837e JC |
142 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
143 | BIT(IIO_CHAN_INFO_SCALE), \ | |
4cd8d874 LPC |
144 | } |
145 | ||
146 | static const struct iio_chan_spec max517_channels[] = { | |
147 | MAX517_CHANNEL(0), | |
a878a1a6 AF |
148 | MAX517_CHANNEL(1), |
149 | MAX517_CHANNEL(2), | |
150 | MAX517_CHANNEL(3), | |
151 | MAX517_CHANNEL(4), | |
152 | MAX517_CHANNEL(5), | |
153 | MAX517_CHANNEL(6), | |
154 | MAX517_CHANNEL(7), | |
6fe8135f JC |
155 | }; |
156 | ||
fc52692c | 157 | static int max517_probe(struct i2c_client *client, |
6ddc5fb4 RS |
158 | const struct i2c_device_id *id) |
159 | { | |
160 | struct max517_data *data; | |
cada11fa | 161 | struct iio_dev *indio_dev; |
6ddc5fb4 | 162 | struct max517_platform_data *platform_data = client->dev.platform_data; |
a878a1a6 | 163 | int chan; |
6ddc5fb4 | 164 | |
cc566fd5 SK |
165 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
166 | if (!indio_dev) | |
167 | return -ENOMEM; | |
cada11fa JC |
168 | data = iio_priv(indio_dev); |
169 | i2c_set_clientdata(client, indio_dev); | |
826514b4 RS |
170 | data->client = client; |
171 | ||
6ddc5fb4 | 172 | /* establish that the iio_dev is a child of the i2c device */ |
cada11fa | 173 | indio_dev->dev.parent = &client->dev; |
6ddc5fb4 | 174 | |
a878a1a6 AF |
175 | switch (id->driver_data) { |
176 | case ID_MAX521: | |
177 | indio_dev->num_channels = 8; | |
178 | break; | |
179 | case ID_MAX520: | |
180 | indio_dev->num_channels = 4; | |
181 | break; | |
182 | case ID_MAX519: | |
183 | case ID_MAX518: | |
4cd8d874 | 184 | indio_dev->num_channels = 2; |
a878a1a6 AF |
185 | break; |
186 | default: /* single channel for MAX517 */ | |
187 | indio_dev->num_channels = 1; | |
188 | break; | |
189 | } | |
4cd8d874 | 190 | indio_dev->channels = max517_channels; |
cada11fa | 191 | indio_dev->modes = INDIO_DIRECT_MODE; |
4cd8d874 | 192 | indio_dev->info = &max517_info; |
6ddc5fb4 RS |
193 | |
194 | /* | |
195 | * Reference voltage on MAX518 and default is 5V, else take vref_mv | |
196 | * from platform_data | |
197 | */ | |
a878a1a6 AF |
198 | for (chan = 0; chan < indio_dev->num_channels; chan++) { |
199 | if (id->driver_data == ID_MAX518 || !platform_data) | |
200 | data->vref_mv[chan] = 5000; /* mV */ | |
201 | else | |
202 | data->vref_mv[chan] = platform_data->vref_mv[chan]; | |
6ddc5fb4 RS |
203 | } |
204 | ||
345d4f92 | 205 | return iio_device_register(indio_dev); |
6ddc5fb4 RS |
206 | } |
207 | ||
fc52692c | 208 | static int max517_remove(struct i2c_client *client) |
6ddc5fb4 | 209 | { |
e8ccc11f | 210 | iio_device_unregister(i2c_get_clientdata(client)); |
6ddc5fb4 RS |
211 | return 0; |
212 | } | |
213 | ||
214 | static const struct i2c_device_id max517_id[] = { | |
215 | { "max517", ID_MAX517 }, | |
216 | { "max518", ID_MAX518 }, | |
217 | { "max519", ID_MAX519 }, | |
a878a1a6 AF |
218 | { "max520", ID_MAX520 }, |
219 | { "max521", ID_MAX521 }, | |
6ddc5fb4 RS |
220 | { } |
221 | }; | |
222 | MODULE_DEVICE_TABLE(i2c, max517_id); | |
223 | ||
224 | static struct i2c_driver max517_driver = { | |
225 | .driver = { | |
226 | .name = MAX517_DRV_NAME, | |
fe8a5420 | 227 | .pm = &max517_pm_ops, |
6ddc5fb4 RS |
228 | }, |
229 | .probe = max517_probe, | |
fc52692c | 230 | .remove = max517_remove, |
6ddc5fb4 RS |
231 | .id_table = max517_id, |
232 | }; | |
6e5af184 | 233 | module_i2c_driver(max517_driver); |
6ddc5fb4 RS |
234 | |
235 | MODULE_AUTHOR("Roland Stigge <[email protected]>"); | |
a878a1a6 | 236 | MODULE_DESCRIPTION("MAX517/518/519/520/521 8-bit DAC"); |
6ddc5fb4 | 237 | MODULE_LICENSE("GPL"); |