]> Git Repo - J-linux.git/blob - drivers/iio/dac/mcp4922.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / iio / dac / mcp4922.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * mcp4922.c
4  *
5  * Driver for Microchip Digital to Analog Converters.
6  * Supports MCP4902, MCP4912, and MCP4922.
7  *
8  * Copyright (c) 2014 EMAC Inc.
9  */
10
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/spi/spi.h>
14 #include <linux/iio/iio.h>
15 #include <linux/iio/sysfs.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/bitops.h>
18
19 #define MCP4922_NUM_CHANNELS    2
20 #define MCP4921_NUM_CHANNELS    1
21
22 enum mcp4922_supported_device_ids {
23         ID_MCP4902,
24         ID_MCP4912,
25         ID_MCP4921,
26         ID_MCP4922,
27 };
28
29 struct mcp4922_state {
30         struct spi_device *spi;
31         unsigned int value[MCP4922_NUM_CHANNELS];
32         unsigned int vref_mv;
33         u8 mosi[2] __aligned(IIO_DMA_MINALIGN);
34 };
35
36 #define MCP4922_CHAN(chan, bits) {                      \
37         .type = IIO_VOLTAGE,                            \
38         .output = 1,                                    \
39         .indexed = 1,                                   \
40         .channel = chan,                                \
41         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
42         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
43         .scan_type = {                                  \
44                 .sign = 'u',                            \
45                 .realbits = (bits),                     \
46                 .storagebits = 16,                      \
47                 .shift = 12 - (bits),                   \
48         },                                              \
49 }
50
51 static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val)
52 {
53         state->mosi[1] = val & 0xff;
54         state->mosi[0] = (addr == 0) ? 0x00 : 0x80;
55         state->mosi[0] |= 0x30 | ((val >> 8) & 0x0f);
56
57         return spi_write(state->spi, state->mosi, 2);
58 }
59
60 static int mcp4922_read_raw(struct iio_dev *indio_dev,
61                 struct iio_chan_spec const *chan,
62                 int *val,
63                 int *val2,
64                 long mask)
65 {
66         struct mcp4922_state *state = iio_priv(indio_dev);
67
68         switch (mask) {
69         case IIO_CHAN_INFO_RAW:
70                 *val = state->value[chan->channel];
71                 return IIO_VAL_INT;
72         case IIO_CHAN_INFO_SCALE:
73                 *val = state->vref_mv;
74                 *val2 = chan->scan_type.realbits;
75                 return IIO_VAL_FRACTIONAL_LOG2;
76         default:
77                 return -EINVAL;
78         }
79 }
80
81 static int mcp4922_write_raw(struct iio_dev *indio_dev,
82                 struct iio_chan_spec const *chan,
83                 int val,
84                 int val2,
85                 long mask)
86 {
87         struct mcp4922_state *state = iio_priv(indio_dev);
88         int ret;
89
90         if (val2 != 0)
91                 return -EINVAL;
92
93         switch (mask) {
94         case IIO_CHAN_INFO_RAW:
95                 if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
96                         return -EINVAL;
97                 val <<= chan->scan_type.shift;
98
99                 ret = mcp4922_spi_write(state, chan->channel, val);
100                 if (!ret)
101                         state->value[chan->channel] = val;
102                 return ret;
103
104         default:
105                 return -EINVAL;
106         }
107 }
108
109 static const struct iio_chan_spec mcp4922_channels[4][MCP4922_NUM_CHANNELS] = {
110         [ID_MCP4902] = { MCP4922_CHAN(0, 8),    MCP4922_CHAN(1, 8) },
111         [ID_MCP4912] = { MCP4922_CHAN(0, 10),   MCP4922_CHAN(1, 10) },
112         [ID_MCP4921] = { MCP4922_CHAN(0, 12),   {} },
113         [ID_MCP4922] = { MCP4922_CHAN(0, 12),   MCP4922_CHAN(1, 12) },
114 };
115
116 static const struct iio_info mcp4922_info = {
117         .read_raw = &mcp4922_read_raw,
118         .write_raw = &mcp4922_write_raw,
119 };
120
121 static int mcp4922_probe(struct spi_device *spi)
122 {
123         struct iio_dev *indio_dev;
124         struct mcp4922_state *state;
125         const struct spi_device_id *id;
126         int ret;
127
128         indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
129         if (indio_dev == NULL)
130                 return -ENOMEM;
131
132         state = iio_priv(indio_dev);
133         state->spi = spi;
134
135         ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
136         if (ret < 0)
137                 return dev_err_probe(&spi->dev, ret, "Failed to get vref voltage\n");
138
139         state->vref_mv = ret / 1000;
140
141         id = spi_get_device_id(spi);
142         indio_dev->info = &mcp4922_info;
143         indio_dev->modes = INDIO_DIRECT_MODE;
144         indio_dev->channels = mcp4922_channels[id->driver_data];
145         if (id->driver_data == ID_MCP4921)
146                 indio_dev->num_channels = MCP4921_NUM_CHANNELS;
147         else
148                 indio_dev->num_channels = MCP4922_NUM_CHANNELS;
149         indio_dev->name = id->name;
150
151         ret = devm_iio_device_register(&spi->dev, indio_dev);
152         if (ret)
153                 return dev_err_probe(&spi->dev, ret, "Failed to register iio device\n");
154
155         return 0;
156 }
157
158
159 static const struct spi_device_id mcp4922_id[] = {
160         {"mcp4902", ID_MCP4902},
161         {"mcp4912", ID_MCP4912},
162         {"mcp4921", ID_MCP4921},
163         {"mcp4922", ID_MCP4922},
164         {}
165 };
166 MODULE_DEVICE_TABLE(spi, mcp4922_id);
167
168 static struct spi_driver mcp4922_driver = {
169         .driver = {
170                    .name = "mcp4922",
171                    },
172         .probe = mcp4922_probe,
173         .id_table = mcp4922_id,
174 };
175 module_spi_driver(mcp4922_driver);
176
177 MODULE_AUTHOR("Michael Welling <[email protected]>");
178 MODULE_DESCRIPTION("Microchip MCP4902, MCP4912, MCP4922 DAC");
179 MODULE_LICENSE("GPL v2");
This page took 0.037234 seconds and 4 git commands to generate.