xref: /linux/drivers/iio/dac/mcp47feb02.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*bf394cc8SAriana Lazar // SPDX-License-Identifier: GPL-2.0+
2*bf394cc8SAriana Lazar /*
3*bf394cc8SAriana Lazar  * IIO driver for MCP47FEB02 Multi-Channel DAC with I2C interface
4*bf394cc8SAriana Lazar  *
5*bf394cc8SAriana Lazar  * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
6*bf394cc8SAriana Lazar  *
7*bf394cc8SAriana Lazar  * Author: Ariana Lazar <ariana.lazar@microchip.com>
8*bf394cc8SAriana Lazar  *
9*bf394cc8SAriana Lazar  * Datasheet links:
10*bf394cc8SAriana Lazar  * [MCP47FEBxx] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005375A.pdf
11*bf394cc8SAriana Lazar  * [MCP47FVBxx] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005405A.pdf
12*bf394cc8SAriana Lazar  * [MCP47FxBx4/8] https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP47FXBX48-Data-Sheet-DS200006368A.pdf
13*bf394cc8SAriana Lazar  */
14*bf394cc8SAriana Lazar #include <linux/array_size.h>
15*bf394cc8SAriana Lazar #include <linux/bits.h>
16*bf394cc8SAriana Lazar #include <linux/bitfield.h>
17*bf394cc8SAriana Lazar #include <linux/delay.h>
18*bf394cc8SAriana Lazar #include <linux/err.h>
19*bf394cc8SAriana Lazar #include <linux/i2c.h>
20*bf394cc8SAriana Lazar #include <linux/iio/iio.h>
21*bf394cc8SAriana Lazar #include <linux/iio/sysfs.h>
22*bf394cc8SAriana Lazar #include <linux/kstrtox.h>
23*bf394cc8SAriana Lazar #include <linux/module.h>
24*bf394cc8SAriana Lazar #include <linux/mod_devicetable.h>
25*bf394cc8SAriana Lazar #include <linux/mutex.h>
26*bf394cc8SAriana Lazar #include <linux/property.h>
27*bf394cc8SAriana Lazar #include <linux/regmap.h>
28*bf394cc8SAriana Lazar #include <linux/regulator/consumer.h>
29*bf394cc8SAriana Lazar #include <linux/time64.h>
30*bf394cc8SAriana Lazar #include <linux/types.h>
31*bf394cc8SAriana Lazar #include <linux/units.h>
32*bf394cc8SAriana Lazar 
33*bf394cc8SAriana Lazar /* Register addresses must be left shifted with 3 positions in order to append command mask */
34*bf394cc8SAriana Lazar #define MCP47FEB02_DAC0_REG_ADDR			0x00
35*bf394cc8SAriana Lazar #define MCP47FEB02_VREF_REG_ADDR			0x40
36*bf394cc8SAriana Lazar #define MCP47FEB02_POWER_DOWN_REG_ADDR			0x48
37*bf394cc8SAriana Lazar #define MCP47FEB02_DAC_CTRL_MASK			GENMASK(1, 0)
38*bf394cc8SAriana Lazar 
39*bf394cc8SAriana Lazar #define MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR		0x50
40*bf394cc8SAriana Lazar #define MCP47FEB02_GAIN_BIT_MASK			BIT(0)
41*bf394cc8SAriana Lazar #define MCP47FEB02_GAIN_BIT_STATUS_EEWA_MASK		BIT(6)
42*bf394cc8SAriana Lazar #define MCP47FEB02_GAIN_BITS_MASK			GENMASK(15, 8)
43*bf394cc8SAriana Lazar 
44*bf394cc8SAriana Lazar #define MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR		0x58
45*bf394cc8SAriana Lazar 
46*bf394cc8SAriana Lazar #define MCP47FEB02_NV_DAC0_REG_ADDR			0x80
47*bf394cc8SAriana Lazar #define MCP47FEB02_NV_VREF_REG_ADDR			0xC0
48*bf394cc8SAriana Lazar #define MCP47FEB02_NV_POWER_DOWN_REG_ADDR		0xC8
49*bf394cc8SAriana Lazar #define MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR	0xD0
50*bf394cc8SAriana Lazar #define MCP47FEB02_NV_I2C_SLAVE_ADDR_MASK		GENMASK(7, 0)
51*bf394cc8SAriana Lazar 
52*bf394cc8SAriana Lazar /* Voltage reference, Power-Down control register and DAC Wiperlock status register fields */
53*bf394cc8SAriana Lazar #define DAC_CTRL_MASK(ch)				(GENMASK(1, 0) << (2 * (ch)))
54*bf394cc8SAriana Lazar #define DAC_CTRL_VAL(ch, val)				((val) << (2 * (ch)))
55*bf394cc8SAriana Lazar 
56*bf394cc8SAriana Lazar /* Gain Control and I2C Slave Address Reguster fields */
57*bf394cc8SAriana Lazar #define DAC_GAIN_MASK(ch)				(BIT(0) << (8 + (ch)))
58*bf394cc8SAriana Lazar #define DAC_GAIN_VAL(ch, val)				((val) << (8 + (ch)))
59*bf394cc8SAriana Lazar 
60*bf394cc8SAriana Lazar #define REG_ADDR(reg)					((reg) << 3)
61*bf394cc8SAriana Lazar #define NV_REG_ADDR(reg)				((NV_DAC_ADDR_OFFSET + (reg)) << 3)
62*bf394cc8SAriana Lazar #define READFLAG_MASK					GENMASK(2, 1)
63*bf394cc8SAriana Lazar 
64*bf394cc8SAriana Lazar #define MCP47FEB02_MAX_CH				8
65*bf394cc8SAriana Lazar #define MCP47FEB02_MAX_SCALES_CH			3
66*bf394cc8SAriana Lazar #define MCP47FEB02_DAC_WIPER_UNLOCKED			0
67*bf394cc8SAriana Lazar #define MCP47FEB02_NORMAL_OPERATION			0
68*bf394cc8SAriana Lazar #define MCP47FEB02_INTERNAL_BAND_GAP_mV			2440
69*bf394cc8SAriana Lazar #define NV_DAC_ADDR_OFFSET				0x10
70*bf394cc8SAriana Lazar 
71*bf394cc8SAriana Lazar enum mcp47feb02_vref_mode {
72*bf394cc8SAriana Lazar 	MCP47FEB02_VREF_VDD = 0,
73*bf394cc8SAriana Lazar 	MCP47FEB02_INTERNAL_BAND_GAP = 1,
74*bf394cc8SAriana Lazar 	MCP47FEB02_EXTERNAL_VREF_UNBUFFERED = 2,
75*bf394cc8SAriana Lazar 	MCP47FEB02_EXTERNAL_VREF_BUFFERED = 3,
76*bf394cc8SAriana Lazar };
77*bf394cc8SAriana Lazar 
78*bf394cc8SAriana Lazar enum mcp47feb02_scale {
79*bf394cc8SAriana Lazar 	MCP47FEB02_SCALE_VDD = 0,
80*bf394cc8SAriana Lazar 	MCP47FEB02_SCALE_GAIN_X1 = 1,
81*bf394cc8SAriana Lazar 	MCP47FEB02_SCALE_GAIN_X2 = 2,
82*bf394cc8SAriana Lazar };
83*bf394cc8SAriana Lazar 
84*bf394cc8SAriana Lazar enum mcp47feb02_gain_bit_mode {
85*bf394cc8SAriana Lazar 	MCP47FEB02_GAIN_BIT_X1 = 0,
86*bf394cc8SAriana Lazar 	MCP47FEB02_GAIN_BIT_X2 = 1,
87*bf394cc8SAriana Lazar };
88*bf394cc8SAriana Lazar 
89*bf394cc8SAriana Lazar static const char * const mcp47feb02_powerdown_modes[] = {
90*bf394cc8SAriana Lazar 	"1kohm_to_gnd",
91*bf394cc8SAriana Lazar 	"100kohm_to_gnd",
92*bf394cc8SAriana Lazar 	"open_circuit",
93*bf394cc8SAriana Lazar };
94*bf394cc8SAriana Lazar 
95*bf394cc8SAriana Lazar /**
96*bf394cc8SAriana Lazar  * struct mcp47feb02_features - chip specific data
97*bf394cc8SAriana Lazar  * @name: device name
98*bf394cc8SAriana Lazar  * @phys_channels: number of hardware channels
99*bf394cc8SAriana Lazar  * @resolution: DAC resolution
100*bf394cc8SAriana Lazar  * @have_ext_vref1: does the hardware have an the second external voltage reference?
101*bf394cc8SAriana Lazar  * @have_eeprom: does the hardware have an internal eeprom?
102*bf394cc8SAriana Lazar  */
103*bf394cc8SAriana Lazar struct mcp47feb02_features {
104*bf394cc8SAriana Lazar 	const char *name;
105*bf394cc8SAriana Lazar 	unsigned int phys_channels;
106*bf394cc8SAriana Lazar 	unsigned int resolution;
107*bf394cc8SAriana Lazar 	bool have_ext_vref1;
108*bf394cc8SAriana Lazar 	bool have_eeprom;
109*bf394cc8SAriana Lazar };
110*bf394cc8SAriana Lazar 
111*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb01_chip_features = {
112*bf394cc8SAriana Lazar 	.name = "mcp47feb01",
113*bf394cc8SAriana Lazar 	.phys_channels = 1,
114*bf394cc8SAriana Lazar 	.resolution = 8,
115*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
116*bf394cc8SAriana Lazar 	.have_eeprom = true,
117*bf394cc8SAriana Lazar };
118*bf394cc8SAriana Lazar 
119*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb02_chip_features = {
120*bf394cc8SAriana Lazar 	.name = "mcp47feb02",
121*bf394cc8SAriana Lazar 	.phys_channels = 2,
122*bf394cc8SAriana Lazar 	.resolution = 8,
123*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
124*bf394cc8SAriana Lazar 	.have_eeprom = true,
125*bf394cc8SAriana Lazar };
126*bf394cc8SAriana Lazar 
127*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb04_chip_features = {
128*bf394cc8SAriana Lazar 	.name = "mcp47feb04",
129*bf394cc8SAriana Lazar 	.phys_channels = 4,
130*bf394cc8SAriana Lazar 	.resolution = 8,
131*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
132*bf394cc8SAriana Lazar 	.have_eeprom = true,
133*bf394cc8SAriana Lazar };
134*bf394cc8SAriana Lazar 
135*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb08_chip_features = {
136*bf394cc8SAriana Lazar 	.name = "mcp47feb08",
137*bf394cc8SAriana Lazar 	.phys_channels = 8,
138*bf394cc8SAriana Lazar 	.resolution = 8,
139*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
140*bf394cc8SAriana Lazar 	.have_eeprom = true,
141*bf394cc8SAriana Lazar };
142*bf394cc8SAriana Lazar 
143*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb11_chip_features = {
144*bf394cc8SAriana Lazar 	.name = "mcp47feb11",
145*bf394cc8SAriana Lazar 	.phys_channels = 1,
146*bf394cc8SAriana Lazar 	.resolution = 10,
147*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
148*bf394cc8SAriana Lazar 	.have_eeprom = true,
149*bf394cc8SAriana Lazar };
150*bf394cc8SAriana Lazar 
151*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb12_chip_features = {
152*bf394cc8SAriana Lazar 	.name = "mcp47feb12",
153*bf394cc8SAriana Lazar 	.phys_channels = 2,
154*bf394cc8SAriana Lazar 	.resolution = 10,
155*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
156*bf394cc8SAriana Lazar 	.have_eeprom = true,
157*bf394cc8SAriana Lazar };
158*bf394cc8SAriana Lazar 
159*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb14_chip_features = {
160*bf394cc8SAriana Lazar 	.name = "mcp47feb14",
161*bf394cc8SAriana Lazar 	.phys_channels = 4,
162*bf394cc8SAriana Lazar 	.resolution = 10,
163*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
164*bf394cc8SAriana Lazar 	.have_eeprom = true,
165*bf394cc8SAriana Lazar };
166*bf394cc8SAriana Lazar 
167*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb18_chip_features = {
168*bf394cc8SAriana Lazar 	.name = "mcp47feb18",
169*bf394cc8SAriana Lazar 	.phys_channels = 8,
170*bf394cc8SAriana Lazar 	.resolution = 10,
171*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
172*bf394cc8SAriana Lazar 	.have_eeprom = true,
173*bf394cc8SAriana Lazar };
174*bf394cc8SAriana Lazar 
175*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb21_chip_features = {
176*bf394cc8SAriana Lazar 	.name = "mcp47feb21",
177*bf394cc8SAriana Lazar 	.phys_channels = 1,
178*bf394cc8SAriana Lazar 	.resolution = 12,
179*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
180*bf394cc8SAriana Lazar 	.have_eeprom = true,
181*bf394cc8SAriana Lazar };
182*bf394cc8SAriana Lazar 
183*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb22_chip_features = {
184*bf394cc8SAriana Lazar 	.name = "mcp47feb22",
185*bf394cc8SAriana Lazar 	.phys_channels = 2,
186*bf394cc8SAriana Lazar 	.resolution = 12,
187*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
188*bf394cc8SAriana Lazar 	.have_eeprom = true,
189*bf394cc8SAriana Lazar };
190*bf394cc8SAriana Lazar 
191*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb24_chip_features = {
192*bf394cc8SAriana Lazar 	.name = "mcp47feb24",
193*bf394cc8SAriana Lazar 	.phys_channels = 4,
194*bf394cc8SAriana Lazar 	.resolution = 12,
195*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
196*bf394cc8SAriana Lazar 	.have_eeprom = true,
197*bf394cc8SAriana Lazar };
198*bf394cc8SAriana Lazar 
199*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47feb28_chip_features = {
200*bf394cc8SAriana Lazar 	.name = "mcp47feb28",
201*bf394cc8SAriana Lazar 	.phys_channels = 8,
202*bf394cc8SAriana Lazar 	.resolution = 12,
203*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
204*bf394cc8SAriana Lazar 	.have_eeprom = true,
205*bf394cc8SAriana Lazar };
206*bf394cc8SAriana Lazar 
207*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb01_chip_features = {
208*bf394cc8SAriana Lazar 	.name = "mcp47fvb01",
209*bf394cc8SAriana Lazar 	.phys_channels = 1,
210*bf394cc8SAriana Lazar 	.resolution = 8,
211*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
212*bf394cc8SAriana Lazar 	.have_eeprom = false,
213*bf394cc8SAriana Lazar };
214*bf394cc8SAriana Lazar 
215*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb02_chip_features = {
216*bf394cc8SAriana Lazar 	.name = "mcp47fvb02",
217*bf394cc8SAriana Lazar 	.phys_channels = 2,
218*bf394cc8SAriana Lazar 	.resolution = 8,
219*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
220*bf394cc8SAriana Lazar 	.have_eeprom = false,
221*bf394cc8SAriana Lazar };
222*bf394cc8SAriana Lazar 
223*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb04_chip_features = {
224*bf394cc8SAriana Lazar 	.name = "mcp47fvb04",
225*bf394cc8SAriana Lazar 	.phys_channels = 4,
226*bf394cc8SAriana Lazar 	.resolution = 8,
227*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
228*bf394cc8SAriana Lazar 	.have_eeprom = false,
229*bf394cc8SAriana Lazar };
230*bf394cc8SAriana Lazar 
231*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb08_chip_features = {
232*bf394cc8SAriana Lazar 	.name = "mcp47fvb08",
233*bf394cc8SAriana Lazar 	.phys_channels = 8,
234*bf394cc8SAriana Lazar 	.resolution = 8,
235*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
236*bf394cc8SAriana Lazar 	.have_eeprom = false,
237*bf394cc8SAriana Lazar };
238*bf394cc8SAriana Lazar 
239*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb11_chip_features = {
240*bf394cc8SAriana Lazar 	.name = "mcp47fvb11",
241*bf394cc8SAriana Lazar 	.phys_channels = 1,
242*bf394cc8SAriana Lazar 	.resolution = 10,
243*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
244*bf394cc8SAriana Lazar 	.have_eeprom = false,
245*bf394cc8SAriana Lazar };
246*bf394cc8SAriana Lazar 
247*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb12_chip_features = {
248*bf394cc8SAriana Lazar 	.name = "mcp47fvb12",
249*bf394cc8SAriana Lazar 	.phys_channels = 2,
250*bf394cc8SAriana Lazar 	.resolution = 10,
251*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
252*bf394cc8SAriana Lazar 	.have_eeprom = false,
253*bf394cc8SAriana Lazar };
254*bf394cc8SAriana Lazar 
255*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb14_chip_features = {
256*bf394cc8SAriana Lazar 	.name = "mcp47fvb14",
257*bf394cc8SAriana Lazar 	.phys_channels = 4,
258*bf394cc8SAriana Lazar 	.resolution = 10,
259*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
260*bf394cc8SAriana Lazar 	.have_eeprom = false,
261*bf394cc8SAriana Lazar };
262*bf394cc8SAriana Lazar 
263*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb18_chip_features = {
264*bf394cc8SAriana Lazar 	.name = "mcp47fvb18",
265*bf394cc8SAriana Lazar 	.phys_channels = 8,
266*bf394cc8SAriana Lazar 	.resolution = 10,
267*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
268*bf394cc8SAriana Lazar 	.have_eeprom = false,
269*bf394cc8SAriana Lazar };
270*bf394cc8SAriana Lazar 
271*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb21_chip_features = {
272*bf394cc8SAriana Lazar 	.name = "mcp47fvb21",
273*bf394cc8SAriana Lazar 	.phys_channels = 1,
274*bf394cc8SAriana Lazar 	.resolution = 12,
275*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
276*bf394cc8SAriana Lazar 	.have_eeprom = false,
277*bf394cc8SAriana Lazar };
278*bf394cc8SAriana Lazar 
279*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb22_chip_features = {
280*bf394cc8SAriana Lazar 	.name = "mcp47fvb22",
281*bf394cc8SAriana Lazar 	.phys_channels = 2,
282*bf394cc8SAriana Lazar 	.resolution = 12,
283*bf394cc8SAriana Lazar 	.have_ext_vref1 = false,
284*bf394cc8SAriana Lazar 	.have_eeprom = false,
285*bf394cc8SAriana Lazar };
286*bf394cc8SAriana Lazar 
287*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb24_chip_features = {
288*bf394cc8SAriana Lazar 	.name = "mcp47fvb24",
289*bf394cc8SAriana Lazar 	.phys_channels = 4,
290*bf394cc8SAriana Lazar 	.resolution = 12,
291*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
292*bf394cc8SAriana Lazar 	.have_eeprom = false,
293*bf394cc8SAriana Lazar };
294*bf394cc8SAriana Lazar 
295*bf394cc8SAriana Lazar static const struct mcp47feb02_features mcp47fvb28_chip_features = {
296*bf394cc8SAriana Lazar 	.name = "mcp47fvb28",
297*bf394cc8SAriana Lazar 	.phys_channels = 8,
298*bf394cc8SAriana Lazar 	.resolution = 12,
299*bf394cc8SAriana Lazar 	.have_ext_vref1 = true,
300*bf394cc8SAriana Lazar 	.have_eeprom = false,
301*bf394cc8SAriana Lazar };
302*bf394cc8SAriana Lazar 
303*bf394cc8SAriana Lazar /**
304*bf394cc8SAriana Lazar  * struct mcp47feb02_channel_data - channel configuration
305*bf394cc8SAriana Lazar  * @ref_mode: chosen voltage for reference
306*bf394cc8SAriana Lazar  * @use_2x_gain: output driver gain control
307*bf394cc8SAriana Lazar  * @powerdown: is false if the channel is in normal operation mode
308*bf394cc8SAriana Lazar  * @powerdown_mode: selected power-down mode
309*bf394cc8SAriana Lazar  * @dac_data: dac value
310*bf394cc8SAriana Lazar  */
311*bf394cc8SAriana Lazar struct mcp47feb02_channel_data {
312*bf394cc8SAriana Lazar 	u8 ref_mode;
313*bf394cc8SAriana Lazar 	bool use_2x_gain;
314*bf394cc8SAriana Lazar 	bool powerdown;
315*bf394cc8SAriana Lazar 	u8 powerdown_mode;
316*bf394cc8SAriana Lazar 	u16 dac_data;
317*bf394cc8SAriana Lazar };
318*bf394cc8SAriana Lazar 
319*bf394cc8SAriana Lazar /**
320*bf394cc8SAriana Lazar  * struct mcp47feb02_data - chip configuration
321*bf394cc8SAriana Lazar  * @chdata: options configured for each channel on the device
322*bf394cc8SAriana Lazar  * @lock: prevents concurrent reads/writes to driver's state members
323*bf394cc8SAriana Lazar  * @chip_features: pointer to features struct
324*bf394cc8SAriana Lazar  * @scale_1: scales set on channels that are based on Vref1
325*bf394cc8SAriana Lazar  * @scale: scales set on channels that are based on Vref/Vref0
326*bf394cc8SAriana Lazar  * @active_channels_mask: enabled channels
327*bf394cc8SAriana Lazar  * @regmap: regmap for directly accessing device register
328*bf394cc8SAriana Lazar  * @labels: table with channels labels
329*bf394cc8SAriana Lazar  * @phys_channels: physical channels on the device
330*bf394cc8SAriana Lazar  * @vref1_buffered: Vref1 buffer is enabled
331*bf394cc8SAriana Lazar  * @vref_buffered: Vref/Vref0 buffer is enabled
332*bf394cc8SAriana Lazar  * @use_vref1: vref1-supply is defined
333*bf394cc8SAriana Lazar  * @use_vref: vref-supply is defined
334*bf394cc8SAriana Lazar  */
335*bf394cc8SAriana Lazar struct mcp47feb02_data {
336*bf394cc8SAriana Lazar 	struct mcp47feb02_channel_data chdata[MCP47FEB02_MAX_CH];
337*bf394cc8SAriana Lazar 	struct mutex lock; /* prevents concurrent reads/writes to driver's state members */
338*bf394cc8SAriana Lazar 	const struct mcp47feb02_features *chip_features;
339*bf394cc8SAriana Lazar 	int scale_1[2 * MCP47FEB02_MAX_SCALES_CH];
340*bf394cc8SAriana Lazar 	int scale[2 * MCP47FEB02_MAX_SCALES_CH];
341*bf394cc8SAriana Lazar 	unsigned long active_channels_mask;
342*bf394cc8SAriana Lazar 	struct regmap *regmap;
343*bf394cc8SAriana Lazar 	const char *labels[MCP47FEB02_MAX_CH];
344*bf394cc8SAriana Lazar 	u16 phys_channels;
345*bf394cc8SAriana Lazar 	bool vref1_buffered;
346*bf394cc8SAriana Lazar 	bool vref_buffered;
347*bf394cc8SAriana Lazar 	bool use_vref1;
348*bf394cc8SAriana Lazar 	bool use_vref;
349*bf394cc8SAriana Lazar };
350*bf394cc8SAriana Lazar 
351*bf394cc8SAriana Lazar static const struct regmap_range mcp47feb02_readable_ranges[] = {
352*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
353*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_NV_DAC0_REG_ADDR, MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR),
354*bf394cc8SAriana Lazar };
355*bf394cc8SAriana Lazar 
356*bf394cc8SAriana Lazar static const struct regmap_range mcp47feb02_writable_ranges[] = {
357*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
358*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_NV_DAC0_REG_ADDR, MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR),
359*bf394cc8SAriana Lazar };
360*bf394cc8SAriana Lazar 
361*bf394cc8SAriana Lazar static const struct regmap_range mcp47feb02_volatile_ranges[] = {
362*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
363*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_NV_DAC0_REG_ADDR, MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR),
364*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
365*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_NV_DAC0_REG_ADDR, MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR),
366*bf394cc8SAriana Lazar };
367*bf394cc8SAriana Lazar 
368*bf394cc8SAriana Lazar static const struct regmap_access_table mcp47feb02_readable_table = {
369*bf394cc8SAriana Lazar 	.yes_ranges = mcp47feb02_readable_ranges,
370*bf394cc8SAriana Lazar 	.n_yes_ranges = ARRAY_SIZE(mcp47feb02_readable_ranges),
371*bf394cc8SAriana Lazar };
372*bf394cc8SAriana Lazar 
373*bf394cc8SAriana Lazar static const struct regmap_access_table mcp47feb02_writable_table = {
374*bf394cc8SAriana Lazar 	.yes_ranges = mcp47feb02_writable_ranges,
375*bf394cc8SAriana Lazar 	.n_yes_ranges = ARRAY_SIZE(mcp47feb02_writable_ranges),
376*bf394cc8SAriana Lazar };
377*bf394cc8SAriana Lazar 
378*bf394cc8SAriana Lazar static const struct regmap_access_table mcp47feb02_volatile_table = {
379*bf394cc8SAriana Lazar 	.yes_ranges = mcp47feb02_volatile_ranges,
380*bf394cc8SAriana Lazar 	.n_yes_ranges = ARRAY_SIZE(mcp47feb02_volatile_ranges),
381*bf394cc8SAriana Lazar };
382*bf394cc8SAriana Lazar 
383*bf394cc8SAriana Lazar static const struct regmap_config mcp47feb02_regmap_config = {
384*bf394cc8SAriana Lazar 	.name = "mcp47feb02_regmap",
385*bf394cc8SAriana Lazar 	.reg_bits = 8,
386*bf394cc8SAriana Lazar 	.val_bits = 16,
387*bf394cc8SAriana Lazar 	.rd_table = &mcp47feb02_readable_table,
388*bf394cc8SAriana Lazar 	.wr_table = &mcp47feb02_writable_table,
389*bf394cc8SAriana Lazar 	.volatile_table = &mcp47feb02_volatile_table,
390*bf394cc8SAriana Lazar 	.max_register = MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR,
391*bf394cc8SAriana Lazar 	.read_flag_mask = READFLAG_MASK,
392*bf394cc8SAriana Lazar 	.cache_type = REGCACHE_MAPLE,
393*bf394cc8SAriana Lazar 	.val_format_endian = REGMAP_ENDIAN_BIG,
394*bf394cc8SAriana Lazar };
395*bf394cc8SAriana Lazar 
396*bf394cc8SAriana Lazar /* For devices that doesn't have nonvolatile memory */
397*bf394cc8SAriana Lazar static const struct regmap_range mcp47fvb02_readable_ranges[] = {
398*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
399*bf394cc8SAriana Lazar };
400*bf394cc8SAriana Lazar 
401*bf394cc8SAriana Lazar static const struct regmap_range mcp47fvb02_writable_ranges[] = {
402*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
403*bf394cc8SAriana Lazar };
404*bf394cc8SAriana Lazar 
405*bf394cc8SAriana Lazar static const struct regmap_range mcp47fvb02_volatile_ranges[] = {
406*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
407*bf394cc8SAriana Lazar 	regmap_reg_range(MCP47FEB02_DAC0_REG_ADDR, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR),
408*bf394cc8SAriana Lazar };
409*bf394cc8SAriana Lazar 
410*bf394cc8SAriana Lazar static const struct regmap_access_table mcp47fvb02_readable_table = {
411*bf394cc8SAriana Lazar 	.yes_ranges = mcp47fvb02_readable_ranges,
412*bf394cc8SAriana Lazar 	.n_yes_ranges = ARRAY_SIZE(mcp47fvb02_readable_ranges),
413*bf394cc8SAriana Lazar };
414*bf394cc8SAriana Lazar 
415*bf394cc8SAriana Lazar static const struct regmap_access_table mcp47fvb02_writable_table = {
416*bf394cc8SAriana Lazar 	.yes_ranges = mcp47fvb02_writable_ranges,
417*bf394cc8SAriana Lazar 	.n_yes_ranges = ARRAY_SIZE(mcp47fvb02_writable_ranges),
418*bf394cc8SAriana Lazar };
419*bf394cc8SAriana Lazar 
420*bf394cc8SAriana Lazar static const struct regmap_access_table mcp47fvb02_volatile_table = {
421*bf394cc8SAriana Lazar 	.yes_ranges = mcp47fvb02_volatile_ranges,
422*bf394cc8SAriana Lazar 	.n_yes_ranges = ARRAY_SIZE(mcp47fvb02_volatile_ranges),
423*bf394cc8SAriana Lazar };
424*bf394cc8SAriana Lazar 
425*bf394cc8SAriana Lazar static const struct regmap_config mcp47fvb02_regmap_config = {
426*bf394cc8SAriana Lazar 	.name = "mcp47fvb02_regmap",
427*bf394cc8SAriana Lazar 	.reg_bits = 8,
428*bf394cc8SAriana Lazar 	.val_bits = 16,
429*bf394cc8SAriana Lazar 	.rd_table = &mcp47fvb02_readable_table,
430*bf394cc8SAriana Lazar 	.wr_table = &mcp47fvb02_writable_table,
431*bf394cc8SAriana Lazar 	.volatile_table = &mcp47fvb02_volatile_table,
432*bf394cc8SAriana Lazar 	.max_register = MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR,
433*bf394cc8SAriana Lazar 	.read_flag_mask = READFLAG_MASK,
434*bf394cc8SAriana Lazar 	.cache_type = REGCACHE_MAPLE,
435*bf394cc8SAriana Lazar 	.val_format_endian = REGMAP_ENDIAN_BIG,
436*bf394cc8SAriana Lazar };
437*bf394cc8SAriana Lazar 
438*bf394cc8SAriana Lazar static int mcp47feb02_write_to_eeprom(struct mcp47feb02_data *data, unsigned int reg,
439*bf394cc8SAriana Lazar 				      unsigned int val)
440*bf394cc8SAriana Lazar {
441*bf394cc8SAriana Lazar 	int eewa_val, ret;
442*bf394cc8SAriana Lazar 
443*bf394cc8SAriana Lazar 	/*
444*bf394cc8SAriana Lazar 	 * Wait until the currently occurring EEPROM Write Cycle is completed.
445*bf394cc8SAriana Lazar 	 * Only serial commands to the volatile memory are allowed.
446*bf394cc8SAriana Lazar 	 */
447*bf394cc8SAriana Lazar 	guard(mutex)(&data->lock);
448*bf394cc8SAriana Lazar 
449*bf394cc8SAriana Lazar 	ret = regmap_read_poll_timeout(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR,
450*bf394cc8SAriana Lazar 				       eewa_val,
451*bf394cc8SAriana Lazar 				       !(eewa_val & MCP47FEB02_GAIN_BIT_STATUS_EEWA_MASK),
452*bf394cc8SAriana Lazar 				       USEC_PER_MSEC, USEC_PER_MSEC * 5);
453*bf394cc8SAriana Lazar 	if (ret)
454*bf394cc8SAriana Lazar 		return ret;
455*bf394cc8SAriana Lazar 
456*bf394cc8SAriana Lazar 	return regmap_write(data->regmap, reg, val);
457*bf394cc8SAriana Lazar }
458*bf394cc8SAriana Lazar 
459*bf394cc8SAriana Lazar static ssize_t store_eeprom_store(struct device *dev, struct device_attribute *attr,
460*bf394cc8SAriana Lazar 				  const char *buf, size_t len)
461*bf394cc8SAriana Lazar {
462*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(dev_to_iio_dev(dev));
463*bf394cc8SAriana Lazar 	unsigned int i, val, val1, eewa_val;
464*bf394cc8SAriana Lazar 	bool state;
465*bf394cc8SAriana Lazar 	int ret;
466*bf394cc8SAriana Lazar 
467*bf394cc8SAriana Lazar 	ret = kstrtobool(buf, &state);
468*bf394cc8SAriana Lazar 	if (ret)
469*bf394cc8SAriana Lazar 		return ret;
470*bf394cc8SAriana Lazar 
471*bf394cc8SAriana Lazar 	if (!state)
472*bf394cc8SAriana Lazar 		return 0;
473*bf394cc8SAriana Lazar 
474*bf394cc8SAriana Lazar 	/*
475*bf394cc8SAriana Lazar 	 * Verify DAC Wiper and DAC Configuration are unlocked. If both are disabled,
476*bf394cc8SAriana Lazar 	 * writing to EEPROM is available.
477*bf394cc8SAriana Lazar 	 */
478*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_WIPERLOCK_STATUS_REG_ADDR, &val);
479*bf394cc8SAriana Lazar 	if (ret)
480*bf394cc8SAriana Lazar 		return ret;
481*bf394cc8SAriana Lazar 
482*bf394cc8SAriana Lazar 	if (val) {
483*bf394cc8SAriana Lazar 		dev_err(dev, "DAC Wiper and DAC Configuration not are unlocked.\n");
484*bf394cc8SAriana Lazar 		return -EINVAL;
485*bf394cc8SAriana Lazar 	}
486*bf394cc8SAriana Lazar 
487*bf394cc8SAriana Lazar 	for_each_set_bit(i, &data->active_channels_mask, data->phys_channels) {
488*bf394cc8SAriana Lazar 		ret = mcp47feb02_write_to_eeprom(data, NV_REG_ADDR(i),
489*bf394cc8SAriana Lazar 						 data->chdata[i].dac_data);
490*bf394cc8SAriana Lazar 		if (ret)
491*bf394cc8SAriana Lazar 			return ret;
492*bf394cc8SAriana Lazar 	}
493*bf394cc8SAriana Lazar 
494*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_VREF_REG_ADDR, &val);
495*bf394cc8SAriana Lazar 	if (ret)
496*bf394cc8SAriana Lazar 		return ret;
497*bf394cc8SAriana Lazar 
498*bf394cc8SAriana Lazar 	ret = mcp47feb02_write_to_eeprom(data, MCP47FEB02_NV_VREF_REG_ADDR, val);
499*bf394cc8SAriana Lazar 	if (ret)
500*bf394cc8SAriana Lazar 		return ret;
501*bf394cc8SAriana Lazar 
502*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR, &val);
503*bf394cc8SAriana Lazar 	if (ret)
504*bf394cc8SAriana Lazar 		return ret;
505*bf394cc8SAriana Lazar 
506*bf394cc8SAriana Lazar 	ret = mcp47feb02_write_to_eeprom(data, MCP47FEB02_NV_POWER_DOWN_REG_ADDR, val);
507*bf394cc8SAriana Lazar 	if (ret)
508*bf394cc8SAriana Lazar 		return ret;
509*bf394cc8SAriana Lazar 
510*bf394cc8SAriana Lazar 	ret = regmap_read_poll_timeout(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR, eewa_val,
511*bf394cc8SAriana Lazar 				       !(eewa_val & MCP47FEB02_GAIN_BIT_STATUS_EEWA_MASK),
512*bf394cc8SAriana Lazar 				       USEC_PER_MSEC, USEC_PER_MSEC * 5);
513*bf394cc8SAriana Lazar 	if (ret)
514*bf394cc8SAriana Lazar 		return ret;
515*bf394cc8SAriana Lazar 
516*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR, &val);
517*bf394cc8SAriana Lazar 	if (ret)
518*bf394cc8SAriana Lazar 		return ret;
519*bf394cc8SAriana Lazar 
520*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR, &val1);
521*bf394cc8SAriana Lazar 	if (ret)
522*bf394cc8SAriana Lazar 		return ret;
523*bf394cc8SAriana Lazar 
524*bf394cc8SAriana Lazar 	ret = mcp47feb02_write_to_eeprom(data, MCP47FEB02_NV_GAIN_CTRL_I2C_SLAVE_REG_ADDR,
525*bf394cc8SAriana Lazar 					 (val1 & MCP47FEB02_GAIN_BITS_MASK) |
526*bf394cc8SAriana Lazar 					 (val & MCP47FEB02_NV_I2C_SLAVE_ADDR_MASK));
527*bf394cc8SAriana Lazar 	if (ret)
528*bf394cc8SAriana Lazar 		return ret;
529*bf394cc8SAriana Lazar 
530*bf394cc8SAriana Lazar 	return len;
531*bf394cc8SAriana Lazar }
532*bf394cc8SAriana Lazar 
533*bf394cc8SAriana Lazar static IIO_DEVICE_ATTR_WO(store_eeprom, 0);
534*bf394cc8SAriana Lazar 
535*bf394cc8SAriana Lazar static struct attribute *mcp47feb02_attributes[] = {
536*bf394cc8SAriana Lazar 	&iio_dev_attr_store_eeprom.dev_attr.attr,
537*bf394cc8SAriana Lazar 	NULL
538*bf394cc8SAriana Lazar };
539*bf394cc8SAriana Lazar 
540*bf394cc8SAriana Lazar static const struct attribute_group mcp47feb02_attribute_group = {
541*bf394cc8SAriana Lazar 	.attrs = mcp47feb02_attributes,
542*bf394cc8SAriana Lazar };
543*bf394cc8SAriana Lazar 
544*bf394cc8SAriana Lazar static int mcp47feb02_suspend(struct device *dev)
545*bf394cc8SAriana Lazar {
546*bf394cc8SAriana Lazar 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
547*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
548*bf394cc8SAriana Lazar 	int ret;
549*bf394cc8SAriana Lazar 	u8 ch;
550*bf394cc8SAriana Lazar 
551*bf394cc8SAriana Lazar 	guard(mutex)(&data->lock);
552*bf394cc8SAriana Lazar 
553*bf394cc8SAriana Lazar 	for_each_set_bit(ch, &data->active_channels_mask, data->phys_channels) {
554*bf394cc8SAriana Lazar 		u8 pd_mode;
555*bf394cc8SAriana Lazar 
556*bf394cc8SAriana Lazar 		data->chdata[ch].powerdown = true;
557*bf394cc8SAriana Lazar 		pd_mode = data->chdata[ch].powerdown_mode + 1;
558*bf394cc8SAriana Lazar 		ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
559*bf394cc8SAriana Lazar 					 DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, pd_mode));
560*bf394cc8SAriana Lazar 		if (ret)
561*bf394cc8SAriana Lazar 			return ret;
562*bf394cc8SAriana Lazar 
563*bf394cc8SAriana Lazar 		ret = regmap_write(data->regmap, REG_ADDR(ch), data->chdata[ch].dac_data);
564*bf394cc8SAriana Lazar 		if (ret)
565*bf394cc8SAriana Lazar 			return ret;
566*bf394cc8SAriana Lazar 	}
567*bf394cc8SAriana Lazar 
568*bf394cc8SAriana Lazar 	return 0;
569*bf394cc8SAriana Lazar }
570*bf394cc8SAriana Lazar 
571*bf394cc8SAriana Lazar static int mcp47feb02_resume(struct device *dev)
572*bf394cc8SAriana Lazar {
573*bf394cc8SAriana Lazar 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
574*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
575*bf394cc8SAriana Lazar 	u8 ch;
576*bf394cc8SAriana Lazar 
577*bf394cc8SAriana Lazar 	guard(mutex)(&data->lock);
578*bf394cc8SAriana Lazar 
579*bf394cc8SAriana Lazar 	for_each_set_bit(ch, &data->active_channels_mask, data->phys_channels) {
580*bf394cc8SAriana Lazar 		u8 pd_mode;
581*bf394cc8SAriana Lazar 		int ret;
582*bf394cc8SAriana Lazar 
583*bf394cc8SAriana Lazar 		data->chdata[ch].powerdown = false;
584*bf394cc8SAriana Lazar 		pd_mode = data->chdata[ch].powerdown_mode + 1;
585*bf394cc8SAriana Lazar 
586*bf394cc8SAriana Lazar 		ret = regmap_write(data->regmap, REG_ADDR(ch), data->chdata[ch].dac_data);
587*bf394cc8SAriana Lazar 		if (ret)
588*bf394cc8SAriana Lazar 			return ret;
589*bf394cc8SAriana Lazar 
590*bf394cc8SAriana Lazar 		ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
591*bf394cc8SAriana Lazar 					 DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, pd_mode));
592*bf394cc8SAriana Lazar 		if (ret)
593*bf394cc8SAriana Lazar 			return ret;
594*bf394cc8SAriana Lazar 
595*bf394cc8SAriana Lazar 		ret = regmap_update_bits(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR,
596*bf394cc8SAriana Lazar 					 DAC_GAIN_MASK(ch),
597*bf394cc8SAriana Lazar 					 DAC_GAIN_VAL(ch, data->chdata[ch].use_2x_gain));
598*bf394cc8SAriana Lazar 		if (ret)
599*bf394cc8SAriana Lazar 			return ret;
600*bf394cc8SAriana Lazar 
601*bf394cc8SAriana Lazar 		ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
602*bf394cc8SAriana Lazar 					 DAC_CTRL_MASK(ch),
603*bf394cc8SAriana Lazar 					 DAC_CTRL_VAL(ch, MCP47FEB02_NORMAL_OPERATION));
604*bf394cc8SAriana Lazar 		if (ret)
605*bf394cc8SAriana Lazar 			return ret;
606*bf394cc8SAriana Lazar 	}
607*bf394cc8SAriana Lazar 
608*bf394cc8SAriana Lazar 	return 0;
609*bf394cc8SAriana Lazar }
610*bf394cc8SAriana Lazar 
611*bf394cc8SAriana Lazar static int mcp47feb02_get_powerdown_mode(struct iio_dev *indio_dev,
612*bf394cc8SAriana Lazar 					 const struct iio_chan_spec *chan)
613*bf394cc8SAriana Lazar {
614*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
615*bf394cc8SAriana Lazar 
616*bf394cc8SAriana Lazar 	return data->chdata[chan->address].powerdown_mode;
617*bf394cc8SAriana Lazar }
618*bf394cc8SAriana Lazar 
619*bf394cc8SAriana Lazar static int mcp47feb02_set_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *ch,
620*bf394cc8SAriana Lazar 					 unsigned int mode)
621*bf394cc8SAriana Lazar {
622*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
623*bf394cc8SAriana Lazar 
624*bf394cc8SAriana Lazar 	data->chdata[ch->address].powerdown_mode = mode;
625*bf394cc8SAriana Lazar 
626*bf394cc8SAriana Lazar 	return 0;
627*bf394cc8SAriana Lazar }
628*bf394cc8SAriana Lazar 
629*bf394cc8SAriana Lazar static ssize_t mcp47feb02_read_powerdown(struct iio_dev *indio_dev, uintptr_t private,
630*bf394cc8SAriana Lazar 					 const struct iio_chan_spec *ch, char *buf)
631*bf394cc8SAriana Lazar {
632*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
633*bf394cc8SAriana Lazar 
634*bf394cc8SAriana Lazar 	/* Print if channel is in a power-down mode or not */
635*bf394cc8SAriana Lazar 	return sysfs_emit(buf, "%d\n", data->chdata[ch->address].powerdown);
636*bf394cc8SAriana Lazar }
637*bf394cc8SAriana Lazar 
638*bf394cc8SAriana Lazar static ssize_t mcp47feb02_write_powerdown(struct iio_dev *indio_dev, uintptr_t private,
639*bf394cc8SAriana Lazar 					  const struct iio_chan_spec *ch, const char *buf,
640*bf394cc8SAriana Lazar 					  size_t len)
641*bf394cc8SAriana Lazar {
642*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
643*bf394cc8SAriana Lazar 	u32 reg = ch->address;
644*bf394cc8SAriana Lazar 	u8 tmp_pd_mode;
645*bf394cc8SAriana Lazar 	bool state;
646*bf394cc8SAriana Lazar 	int ret;
647*bf394cc8SAriana Lazar 
648*bf394cc8SAriana Lazar 	guard(mutex)(&data->lock);
649*bf394cc8SAriana Lazar 
650*bf394cc8SAriana Lazar 	ret = kstrtobool(buf, &state);
651*bf394cc8SAriana Lazar 	if (ret)
652*bf394cc8SAriana Lazar 		return ret;
653*bf394cc8SAriana Lazar 
654*bf394cc8SAriana Lazar 	/*
655*bf394cc8SAriana Lazar 	 * Set the channel to the specified power-down mode. Exiting power-down mode
656*bf394cc8SAriana Lazar 	 * requires writing normal operation mode (0) to the channel-specific register bits.
657*bf394cc8SAriana Lazar 	 */
658*bf394cc8SAriana Lazar 	tmp_pd_mode = state ? (data->chdata[reg].powerdown_mode + 1) : MCP47FEB02_NORMAL_OPERATION;
659*bf394cc8SAriana Lazar 	ret = regmap_update_bits(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR,
660*bf394cc8SAriana Lazar 				 DAC_CTRL_MASK(reg), DAC_CTRL_VAL(reg, tmp_pd_mode));
661*bf394cc8SAriana Lazar 	if (ret)
662*bf394cc8SAriana Lazar 		return ret;
663*bf394cc8SAriana Lazar 
664*bf394cc8SAriana Lazar 	data->chdata[reg].powerdown = state;
665*bf394cc8SAriana Lazar 
666*bf394cc8SAriana Lazar 	return len;
667*bf394cc8SAriana Lazar }
668*bf394cc8SAriana Lazar 
669*bf394cc8SAriana Lazar static DEFINE_SIMPLE_DEV_PM_OPS(mcp47feb02_pm_ops, mcp47feb02_suspend, mcp47feb02_resume);
670*bf394cc8SAriana Lazar 
671*bf394cc8SAriana Lazar static const struct iio_enum mcp47febxx_powerdown_mode_enum = {
672*bf394cc8SAriana Lazar 	.items = mcp47feb02_powerdown_modes,
673*bf394cc8SAriana Lazar 	.num_items = ARRAY_SIZE(mcp47feb02_powerdown_modes),
674*bf394cc8SAriana Lazar 	.get = mcp47feb02_get_powerdown_mode,
675*bf394cc8SAriana Lazar 	.set = mcp47feb02_set_powerdown_mode,
676*bf394cc8SAriana Lazar };
677*bf394cc8SAriana Lazar 
678*bf394cc8SAriana Lazar static const struct iio_chan_spec_ext_info mcp47feb02_ext_info[] = {
679*bf394cc8SAriana Lazar 	{
680*bf394cc8SAriana Lazar 		.name = "powerdown",
681*bf394cc8SAriana Lazar 		.read = mcp47feb02_read_powerdown,
682*bf394cc8SAriana Lazar 		.write = mcp47feb02_write_powerdown,
683*bf394cc8SAriana Lazar 		.shared = IIO_SEPARATE,
684*bf394cc8SAriana Lazar 	},
685*bf394cc8SAriana Lazar 	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp47febxx_powerdown_mode_enum),
686*bf394cc8SAriana Lazar 	IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &mcp47febxx_powerdown_mode_enum),
687*bf394cc8SAriana Lazar 	{ }
688*bf394cc8SAriana Lazar };
689*bf394cc8SAriana Lazar 
690*bf394cc8SAriana Lazar static const struct iio_chan_spec mcp47febxx_ch_template = {
691*bf394cc8SAriana Lazar 	.type = IIO_VOLTAGE,
692*bf394cc8SAriana Lazar 	.output = 1,
693*bf394cc8SAriana Lazar 	.indexed = 1,
694*bf394cc8SAriana Lazar 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
695*bf394cc8SAriana Lazar 	.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
696*bf394cc8SAriana Lazar 	.ext_info = mcp47feb02_ext_info,
697*bf394cc8SAriana Lazar };
698*bf394cc8SAriana Lazar 
699*bf394cc8SAriana Lazar static void mcp47feb02_init_scale(struct mcp47feb02_data *data, enum mcp47feb02_scale scale,
700*bf394cc8SAriana Lazar 				  int vref_mV, int scale_avail[])
701*bf394cc8SAriana Lazar {
702*bf394cc8SAriana Lazar 	u32 value_micro, value_int;
703*bf394cc8SAriana Lazar 	u64 tmp;
704*bf394cc8SAriana Lazar 
705*bf394cc8SAriana Lazar 	/* vref_mV should not be negative */
706*bf394cc8SAriana Lazar 	tmp = (u64)vref_mV * MICRO >> data->chip_features->resolution;
707*bf394cc8SAriana Lazar 	value_int = div_u64_rem(tmp, MICRO, &value_micro);
708*bf394cc8SAriana Lazar 	scale_avail[scale * 2] = value_int;
709*bf394cc8SAriana Lazar 	scale_avail[scale * 2 + 1] = value_micro;
710*bf394cc8SAriana Lazar }
711*bf394cc8SAriana Lazar 
712*bf394cc8SAriana Lazar static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_mV,
713*bf394cc8SAriana Lazar 					int vref_mV, int vref1_mV)
714*bf394cc8SAriana Lazar {
715*bf394cc8SAriana Lazar 	struct device *dev = regmap_get_device(data->regmap);
716*bf394cc8SAriana Lazar 	int tmp_vref;
717*bf394cc8SAriana Lazar 
718*bf394cc8SAriana Lazar 	mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale);
719*bf394cc8SAriana Lazar 
720*bf394cc8SAriana Lazar 	if (data->use_vref)
721*bf394cc8SAriana Lazar 		tmp_vref = vref_mV;
722*bf394cc8SAriana Lazar 	else
723*bf394cc8SAriana Lazar 		tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV;
724*bf394cc8SAriana Lazar 
725*bf394cc8SAriana Lazar 	mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale);
726*bf394cc8SAriana Lazar 	mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X2, tmp_vref * 2, data->scale);
727*bf394cc8SAriana Lazar 
728*bf394cc8SAriana Lazar 	if (data->phys_channels >= 4) {
729*bf394cc8SAriana Lazar 		mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale_1);
730*bf394cc8SAriana Lazar 
731*bf394cc8SAriana Lazar 		if (data->use_vref1 && vref1_mV <= 0)
732*bf394cc8SAriana Lazar 			return dev_err_probe(dev, vref1_mV, "Invalid voltage for Vref1\n");
733*bf394cc8SAriana Lazar 
734*bf394cc8SAriana Lazar 		if (data->use_vref1)
735*bf394cc8SAriana Lazar 			tmp_vref = vref1_mV;
736*bf394cc8SAriana Lazar 		else
737*bf394cc8SAriana Lazar 			tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV;
738*bf394cc8SAriana Lazar 
739*bf394cc8SAriana Lazar 		mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1,
740*bf394cc8SAriana Lazar 				      tmp_vref, data->scale_1);
741*bf394cc8SAriana Lazar 		mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X2,
742*bf394cc8SAriana Lazar 				      tmp_vref * 2, data->scale_1);
743*bf394cc8SAriana Lazar 	}
744*bf394cc8SAriana Lazar 
745*bf394cc8SAriana Lazar 	return 0;
746*bf394cc8SAriana Lazar }
747*bf394cc8SAriana Lazar 
748*bf394cc8SAriana Lazar static int mcp47feb02_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *ch,
749*bf394cc8SAriana Lazar 				 const int **vals, int *type, int *length, long info)
750*bf394cc8SAriana Lazar {
751*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
752*bf394cc8SAriana Lazar 
753*bf394cc8SAriana Lazar 	switch (info) {
754*bf394cc8SAriana Lazar 	case IIO_CHAN_INFO_SCALE:
755*bf394cc8SAriana Lazar 		switch (ch->type) {
756*bf394cc8SAriana Lazar 		case IIO_VOLTAGE:
757*bf394cc8SAriana Lazar 			if (data->phys_channels >= 4 && (ch->address % 2))
758*bf394cc8SAriana Lazar 				*vals = data->scale_1;
759*bf394cc8SAriana Lazar 			else
760*bf394cc8SAriana Lazar 				*vals = data->scale;
761*bf394cc8SAriana Lazar 
762*bf394cc8SAriana Lazar 			*length = 2 * MCP47FEB02_MAX_SCALES_CH;
763*bf394cc8SAriana Lazar 			*type = IIO_VAL_INT_PLUS_MICRO;
764*bf394cc8SAriana Lazar 			return IIO_AVAIL_LIST;
765*bf394cc8SAriana Lazar 		default:
766*bf394cc8SAriana Lazar 			return -EINVAL;
767*bf394cc8SAriana Lazar 		}
768*bf394cc8SAriana Lazar 	default:
769*bf394cc8SAriana Lazar 		return -EINVAL;
770*bf394cc8SAriana Lazar 	}
771*bf394cc8SAriana Lazar }
772*bf394cc8SAriana Lazar 
773*bf394cc8SAriana Lazar static void mcp47feb02_get_scale(int ch, struct mcp47feb02_data *data, int *val, int *val2)
774*bf394cc8SAriana Lazar {
775*bf394cc8SAriana Lazar 	enum mcp47feb02_scale current_scale;
776*bf394cc8SAriana Lazar 
777*bf394cc8SAriana Lazar 	if (data->chdata[ch].ref_mode == MCP47FEB02_VREF_VDD)
778*bf394cc8SAriana Lazar 		current_scale = MCP47FEB02_SCALE_VDD;
779*bf394cc8SAriana Lazar 	else if (data->chdata[ch].use_2x_gain)
780*bf394cc8SAriana Lazar 		current_scale = MCP47FEB02_SCALE_GAIN_X2;
781*bf394cc8SAriana Lazar 	else
782*bf394cc8SAriana Lazar 		current_scale = MCP47FEB02_SCALE_GAIN_X1;
783*bf394cc8SAriana Lazar 
784*bf394cc8SAriana Lazar 	if (data->phys_channels >= 4 && (ch % 2)) {
785*bf394cc8SAriana Lazar 		*val = data->scale_1[current_scale * 2];
786*bf394cc8SAriana Lazar 		*val2 = data->scale_1[current_scale * 2 + 1];
787*bf394cc8SAriana Lazar 	} else {
788*bf394cc8SAriana Lazar 		*val = data->scale[current_scale * 2];
789*bf394cc8SAriana Lazar 		*val2 = data->scale[current_scale * 2 + 1];
790*bf394cc8SAriana Lazar 	}
791*bf394cc8SAriana Lazar }
792*bf394cc8SAriana Lazar 
793*bf394cc8SAriana Lazar static int mcp47feb02_check_scale(struct mcp47feb02_data *data, int val, int val2, int scale[])
794*bf394cc8SAriana Lazar {
795*bf394cc8SAriana Lazar 	unsigned int i;
796*bf394cc8SAriana Lazar 
797*bf394cc8SAriana Lazar 	for (i = 0; i < MCP47FEB02_MAX_SCALES_CH; i++) {
798*bf394cc8SAriana Lazar 		if (scale[i * 2] == val && scale[i * 2 + 1] == val2)
799*bf394cc8SAriana Lazar 			return i;
800*bf394cc8SAriana Lazar 	}
801*bf394cc8SAriana Lazar 
802*bf394cc8SAriana Lazar 	return -EINVAL;
803*bf394cc8SAriana Lazar }
804*bf394cc8SAriana Lazar 
805*bf394cc8SAriana Lazar static int mcp47feb02_ch_scale(struct mcp47feb02_data *data, int ch, int scale)
806*bf394cc8SAriana Lazar {
807*bf394cc8SAriana Lazar 	int tmp_val, ret;
808*bf394cc8SAriana Lazar 
809*bf394cc8SAriana Lazar 	if (scale == MCP47FEB02_SCALE_VDD) {
810*bf394cc8SAriana Lazar 		tmp_val = MCP47FEB02_VREF_VDD;
811*bf394cc8SAriana Lazar 	} else if (data->phys_channels >= 4 && (ch % 2)) {
812*bf394cc8SAriana Lazar 		if (data->use_vref1) {
813*bf394cc8SAriana Lazar 			if (data->vref1_buffered)
814*bf394cc8SAriana Lazar 				tmp_val = MCP47FEB02_EXTERNAL_VREF_BUFFERED;
815*bf394cc8SAriana Lazar 			else
816*bf394cc8SAriana Lazar 				tmp_val = MCP47FEB02_EXTERNAL_VREF_UNBUFFERED;
817*bf394cc8SAriana Lazar 		} else {
818*bf394cc8SAriana Lazar 			tmp_val = MCP47FEB02_INTERNAL_BAND_GAP;
819*bf394cc8SAriana Lazar 		}
820*bf394cc8SAriana Lazar 	} else if (data->use_vref) {
821*bf394cc8SAriana Lazar 		if (data->vref_buffered)
822*bf394cc8SAriana Lazar 			tmp_val = MCP47FEB02_EXTERNAL_VREF_BUFFERED;
823*bf394cc8SAriana Lazar 		else
824*bf394cc8SAriana Lazar 			tmp_val = MCP47FEB02_EXTERNAL_VREF_UNBUFFERED;
825*bf394cc8SAriana Lazar 	} else {
826*bf394cc8SAriana Lazar 		tmp_val = MCP47FEB02_INTERNAL_BAND_GAP;
827*bf394cc8SAriana Lazar 	}
828*bf394cc8SAriana Lazar 
829*bf394cc8SAriana Lazar 	ret = regmap_update_bits(data->regmap, MCP47FEB02_VREF_REG_ADDR,
830*bf394cc8SAriana Lazar 				 DAC_CTRL_MASK(ch), DAC_CTRL_VAL(ch, tmp_val));
831*bf394cc8SAriana Lazar 	if (ret)
832*bf394cc8SAriana Lazar 		return ret;
833*bf394cc8SAriana Lazar 
834*bf394cc8SAriana Lazar 	data->chdata[ch].ref_mode = tmp_val;
835*bf394cc8SAriana Lazar 
836*bf394cc8SAriana Lazar 	return 0;
837*bf394cc8SAriana Lazar }
838*bf394cc8SAriana Lazar 
839*bf394cc8SAriana Lazar /*
840*bf394cc8SAriana Lazar  * Setting the scale in order to choose between VDD and (Vref or Band Gap) from the user
841*bf394cc8SAriana Lazar  * space. The VREF pin is either an input or an output, therefore the user cannot
842*bf394cc8SAriana Lazar  * simultaneously connect an external voltage reference to the pin and select the
843*bf394cc8SAriana Lazar  * internal Band Gap.
844*bf394cc8SAriana Lazar  * When the DAC’s voltage reference is configured as the VREF pin, the pin is an input.
845*bf394cc8SAriana Lazar  * When the DAC’s voltage reference is configured as the internal Band Gap,
846*bf394cc8SAriana Lazar  * the VREF pin is an output.
847*bf394cc8SAriana Lazar  * If Vref/Vref1 voltage is not available, then the internal Band Gap will be used
848*bf394cc8SAriana Lazar  * to calculate the values for the scale.
849*bf394cc8SAriana Lazar  */
850*bf394cc8SAriana Lazar static int mcp47feb02_set_scale(struct mcp47feb02_data *data, int ch, int scale)
851*bf394cc8SAriana Lazar {
852*bf394cc8SAriana Lazar 	int tmp_val, ret;
853*bf394cc8SAriana Lazar 
854*bf394cc8SAriana Lazar 	ret = mcp47feb02_ch_scale(data, ch, scale);
855*bf394cc8SAriana Lazar 	if (ret)
856*bf394cc8SAriana Lazar 		return ret;
857*bf394cc8SAriana Lazar 
858*bf394cc8SAriana Lazar 	if (scale == MCP47FEB02_SCALE_GAIN_X2)
859*bf394cc8SAriana Lazar 		tmp_val = MCP47FEB02_GAIN_BIT_X2;
860*bf394cc8SAriana Lazar 	else
861*bf394cc8SAriana Lazar 		tmp_val = MCP47FEB02_GAIN_BIT_X1;
862*bf394cc8SAriana Lazar 
863*bf394cc8SAriana Lazar 	ret = regmap_update_bits(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR,
864*bf394cc8SAriana Lazar 				 DAC_GAIN_MASK(ch), DAC_GAIN_VAL(ch, tmp_val));
865*bf394cc8SAriana Lazar 	if (ret)
866*bf394cc8SAriana Lazar 		return ret;
867*bf394cc8SAriana Lazar 
868*bf394cc8SAriana Lazar 	data->chdata[ch].use_2x_gain = tmp_val;
869*bf394cc8SAriana Lazar 
870*bf394cc8SAriana Lazar 	return 0;
871*bf394cc8SAriana Lazar }
872*bf394cc8SAriana Lazar 
873*bf394cc8SAriana Lazar static int mcp47feb02_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch,
874*bf394cc8SAriana Lazar 			       int *val, int *val2, long mask)
875*bf394cc8SAriana Lazar {
876*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
877*bf394cc8SAriana Lazar 	int ret;
878*bf394cc8SAriana Lazar 
879*bf394cc8SAriana Lazar 	switch (mask) {
880*bf394cc8SAriana Lazar 	case IIO_CHAN_INFO_RAW:
881*bf394cc8SAriana Lazar 		ret = regmap_read(data->regmap, REG_ADDR(ch->address), val);
882*bf394cc8SAriana Lazar 		if (ret)
883*bf394cc8SAriana Lazar 			return ret;
884*bf394cc8SAriana Lazar 		return IIO_VAL_INT;
885*bf394cc8SAriana Lazar 	case IIO_CHAN_INFO_SCALE:
886*bf394cc8SAriana Lazar 		mcp47feb02_get_scale(ch->address, data, val, val2);
887*bf394cc8SAriana Lazar 		return IIO_VAL_INT_PLUS_MICRO;
888*bf394cc8SAriana Lazar 	default:
889*bf394cc8SAriana Lazar 		return -EINVAL;
890*bf394cc8SAriana Lazar 	}
891*bf394cc8SAriana Lazar }
892*bf394cc8SAriana Lazar 
893*bf394cc8SAriana Lazar static int mcp47feb02_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch,
894*bf394cc8SAriana Lazar 				int val, int val2, long mask)
895*bf394cc8SAriana Lazar {
896*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
897*bf394cc8SAriana Lazar 	int *tmp_scale, ret;
898*bf394cc8SAriana Lazar 
899*bf394cc8SAriana Lazar 	guard(mutex)(&data->lock);
900*bf394cc8SAriana Lazar 
901*bf394cc8SAriana Lazar 	switch (mask) {
902*bf394cc8SAriana Lazar 	case IIO_CHAN_INFO_RAW:
903*bf394cc8SAriana Lazar 		ret = regmap_write(data->regmap, REG_ADDR(ch->address), val);
904*bf394cc8SAriana Lazar 		if (ret)
905*bf394cc8SAriana Lazar 			return ret;
906*bf394cc8SAriana Lazar 
907*bf394cc8SAriana Lazar 		data->chdata[ch->address].dac_data = val;
908*bf394cc8SAriana Lazar 		return 0;
909*bf394cc8SAriana Lazar 	case IIO_CHAN_INFO_SCALE:
910*bf394cc8SAriana Lazar 		if (data->phys_channels >= 4 && (ch->address % 2))
911*bf394cc8SAriana Lazar 			tmp_scale = data->scale_1;
912*bf394cc8SAriana Lazar 		else
913*bf394cc8SAriana Lazar 			tmp_scale = data->scale;
914*bf394cc8SAriana Lazar 
915*bf394cc8SAriana Lazar 		ret = mcp47feb02_check_scale(data, val, val2, tmp_scale);
916*bf394cc8SAriana Lazar 		if (ret < 0)
917*bf394cc8SAriana Lazar 			return ret;
918*bf394cc8SAriana Lazar 
919*bf394cc8SAriana Lazar 		return mcp47feb02_set_scale(data, ch->address, ret);
920*bf394cc8SAriana Lazar 	default:
921*bf394cc8SAriana Lazar 		return -EINVAL;
922*bf394cc8SAriana Lazar 	}
923*bf394cc8SAriana Lazar }
924*bf394cc8SAriana Lazar 
925*bf394cc8SAriana Lazar static int mcp47feb02_read_label(struct iio_dev *indio_dev, struct iio_chan_spec const *ch,
926*bf394cc8SAriana Lazar 				 char *label)
927*bf394cc8SAriana Lazar {
928*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
929*bf394cc8SAriana Lazar 
930*bf394cc8SAriana Lazar 	return sysfs_emit(label, "%s\n", data->labels[ch->address]);
931*bf394cc8SAriana Lazar }
932*bf394cc8SAriana Lazar 
933*bf394cc8SAriana Lazar static const struct iio_info mcp47feb02_info = {
934*bf394cc8SAriana Lazar 	.read_raw = mcp47feb02_read_raw,
935*bf394cc8SAriana Lazar 	.write_raw = mcp47feb02_write_raw,
936*bf394cc8SAriana Lazar 	.read_label = mcp47feb02_read_label,
937*bf394cc8SAriana Lazar 	.read_avail = &mcp47feb02_read_avail,
938*bf394cc8SAriana Lazar 	.attrs = &mcp47feb02_attribute_group,
939*bf394cc8SAriana Lazar };
940*bf394cc8SAriana Lazar 
941*bf394cc8SAriana Lazar static const struct iio_info mcp47fvb02_info = {
942*bf394cc8SAriana Lazar 	.read_raw = mcp47feb02_read_raw,
943*bf394cc8SAriana Lazar 	.write_raw = mcp47feb02_write_raw,
944*bf394cc8SAriana Lazar 	.read_label = mcp47feb02_read_label,
945*bf394cc8SAriana Lazar 	.read_avail = &mcp47feb02_read_avail,
946*bf394cc8SAriana Lazar };
947*bf394cc8SAriana Lazar 
948*bf394cc8SAriana Lazar static int mcp47feb02_parse_fw(struct iio_dev *indio_dev,
949*bf394cc8SAriana Lazar 			       const struct mcp47feb02_features *chip_features)
950*bf394cc8SAriana Lazar {
951*bf394cc8SAriana Lazar 	struct iio_chan_spec chanspec = mcp47febxx_ch_template;
952*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data = iio_priv(indio_dev);
953*bf394cc8SAriana Lazar 	struct device *dev = regmap_get_device(data->regmap);
954*bf394cc8SAriana Lazar 	struct iio_chan_spec *channels;
955*bf394cc8SAriana Lazar 	u32 num_channels;
956*bf394cc8SAriana Lazar 	u8 chan_idx = 0;
957*bf394cc8SAriana Lazar 
958*bf394cc8SAriana Lazar 	guard(mutex)(&data->lock);
959*bf394cc8SAriana Lazar 
960*bf394cc8SAriana Lazar 	num_channels = device_get_child_node_count(dev);
961*bf394cc8SAriana Lazar 	if (num_channels > chip_features->phys_channels)
962*bf394cc8SAriana Lazar 		return dev_err_probe(dev, -EINVAL, "More channels than the chip supports\n");
963*bf394cc8SAriana Lazar 
964*bf394cc8SAriana Lazar 	if (!num_channels)
965*bf394cc8SAriana Lazar 		return dev_err_probe(dev, -EINVAL, "No channel specified in the devicetree.\n");
966*bf394cc8SAriana Lazar 
967*bf394cc8SAriana Lazar 	channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL);
968*bf394cc8SAriana Lazar 	if (!channels)
969*bf394cc8SAriana Lazar 		return -ENOMEM;
970*bf394cc8SAriana Lazar 
971*bf394cc8SAriana Lazar 	device_for_each_child_node_scoped(dev, child) {
972*bf394cc8SAriana Lazar 		u32 reg = 0;
973*bf394cc8SAriana Lazar 		int ret;
974*bf394cc8SAriana Lazar 
975*bf394cc8SAriana Lazar 		ret = fwnode_property_read_u32(child, "reg", &reg);
976*bf394cc8SAriana Lazar 		if (ret)
977*bf394cc8SAriana Lazar 			return dev_err_probe(dev, ret, "Invalid channel number\n");
978*bf394cc8SAriana Lazar 
979*bf394cc8SAriana Lazar 		if (reg >= chip_features->phys_channels)
980*bf394cc8SAriana Lazar 			return dev_err_probe(dev, -EINVAL,
981*bf394cc8SAriana Lazar 					     "The index of the channels does not match the chip\n");
982*bf394cc8SAriana Lazar 
983*bf394cc8SAriana Lazar 		set_bit(reg, &data->active_channels_mask);
984*bf394cc8SAriana Lazar 
985*bf394cc8SAriana Lazar 		ret = fwnode_property_read_string(child, "label", &data->labels[reg]);
986*bf394cc8SAriana Lazar 		if (ret)
987*bf394cc8SAriana Lazar 			return dev_err_probe(dev, ret, "%pfw: invalid label\n",
988*bf394cc8SAriana Lazar 					     fwnode_get_name(child));
989*bf394cc8SAriana Lazar 
990*bf394cc8SAriana Lazar 		chanspec.address = reg;
991*bf394cc8SAriana Lazar 		chanspec.channel = reg;
992*bf394cc8SAriana Lazar 		channels[chan_idx] = chanspec;
993*bf394cc8SAriana Lazar 		chan_idx++;
994*bf394cc8SAriana Lazar 	}
995*bf394cc8SAriana Lazar 
996*bf394cc8SAriana Lazar 	indio_dev->num_channels = num_channels;
997*bf394cc8SAriana Lazar 	indio_dev->channels = channels;
998*bf394cc8SAriana Lazar 	indio_dev->modes = INDIO_DIRECT_MODE;
999*bf394cc8SAriana Lazar 	data->phys_channels = chip_features->phys_channels;
1000*bf394cc8SAriana Lazar 
1001*bf394cc8SAriana Lazar 	data->vref_buffered = device_property_read_bool(dev, "microchip,vref-buffered");
1002*bf394cc8SAriana Lazar 
1003*bf394cc8SAriana Lazar 	if (chip_features->have_ext_vref1)
1004*bf394cc8SAriana Lazar 		data->vref1_buffered = device_property_read_bool(dev, "microchip,vref1-buffered");
1005*bf394cc8SAriana Lazar 
1006*bf394cc8SAriana Lazar 	return 0;
1007*bf394cc8SAriana Lazar }
1008*bf394cc8SAriana Lazar 
1009*bf394cc8SAriana Lazar static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
1010*bf394cc8SAriana Lazar {
1011*bf394cc8SAriana Lazar 	unsigned int i, vref_ch, gain_ch, pd_ch;
1012*bf394cc8SAriana Lazar 	int ret;
1013*bf394cc8SAriana Lazar 
1014*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_VREF_REG_ADDR, &vref_ch);
1015*bf394cc8SAriana Lazar 	if (ret)
1016*bf394cc8SAriana Lazar 		return ret;
1017*bf394cc8SAriana Lazar 
1018*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_GAIN_CTRL_STATUS_REG_ADDR, &gain_ch);
1019*bf394cc8SAriana Lazar 	if (ret)
1020*bf394cc8SAriana Lazar 		return ret;
1021*bf394cc8SAriana Lazar 
1022*bf394cc8SAriana Lazar 	ret = regmap_read(data->regmap, MCP47FEB02_POWER_DOWN_REG_ADDR, &pd_ch);
1023*bf394cc8SAriana Lazar 	if (ret)
1024*bf394cc8SAriana Lazar 		return ret;
1025*bf394cc8SAriana Lazar 
1026*bf394cc8SAriana Lazar 	gain_ch = gain_ch & MCP47FEB02_GAIN_BITS_MASK;
1027*bf394cc8SAriana Lazar 	for_each_set_bit(i, &data->active_channels_mask, data->phys_channels) {
1028*bf394cc8SAriana Lazar 		struct device *dev = regmap_get_device(data->regmap);
1029*bf394cc8SAriana Lazar 		unsigned int pd_tmp;
1030*bf394cc8SAriana Lazar 
1031*bf394cc8SAriana Lazar 		data->chdata[i].ref_mode = (vref_ch >> (2 * i)) & MCP47FEB02_DAC_CTRL_MASK;
1032*bf394cc8SAriana Lazar 		data->chdata[i].use_2x_gain = (gain_ch >> i)  & MCP47FEB02_GAIN_BIT_MASK;
1033*bf394cc8SAriana Lazar 
1034*bf394cc8SAriana Lazar 		/*
1035*bf394cc8SAriana Lazar 		 * Inform the user that the current voltage reference read from the volatile
1036*bf394cc8SAriana Lazar 		 * register of the chip is different from the one specified in the device tree.
1037*bf394cc8SAriana Lazar 		 * Considering that the user cannot have an external voltage reference connected
1038*bf394cc8SAriana Lazar 		 * to the pin and select the internal Band Gap at the same time, in order to avoid
1039*bf394cc8SAriana Lazar 		 * miscofiguring the reference voltage, the volatile register will not be written.
1040*bf394cc8SAriana Lazar 		 * In order to overwrite the setting from volatile register with the one from the
1041*bf394cc8SAriana Lazar 		 * device tree, the user needs to write the chosen scale.
1042*bf394cc8SAriana Lazar 		 */
1043*bf394cc8SAriana Lazar 		switch (data->chdata[i].ref_mode) {
1044*bf394cc8SAriana Lazar 		case MCP47FEB02_INTERNAL_BAND_GAP:
1045*bf394cc8SAriana Lazar 			if (data->phys_channels >= 4 && (i % 2) && data->use_vref1) {
1046*bf394cc8SAriana Lazar 				dev_dbg(dev, "ch[%u]: was configured to use internal band gap", i);
1047*bf394cc8SAriana Lazar 				dev_dbg(dev, "ch[%u]: reference voltage set to VREF1", i);
1048*bf394cc8SAriana Lazar 				break;
1049*bf394cc8SAriana Lazar 			}
1050*bf394cc8SAriana Lazar 			if ((data->phys_channels < 4 || (data->phys_channels >= 4 && !(i % 2))) &&
1051*bf394cc8SAriana Lazar 			    data->use_vref) {
1052*bf394cc8SAriana Lazar 				dev_dbg(dev, "ch[%u]: was configured to use internal band gap", i);
1053*bf394cc8SAriana Lazar 				dev_dbg(dev, "ch[%u]: reference voltage set to VREF", i);
1054*bf394cc8SAriana Lazar 				break;
1055*bf394cc8SAriana Lazar 			}
1056*bf394cc8SAriana Lazar 			break;
1057*bf394cc8SAriana Lazar 		case MCP47FEB02_EXTERNAL_VREF_UNBUFFERED:
1058*bf394cc8SAriana Lazar 		case MCP47FEB02_EXTERNAL_VREF_BUFFERED:
1059*bf394cc8SAriana Lazar 			if (data->phys_channels >= 4 && (i % 2) && !data->use_vref1) {
1060*bf394cc8SAriana Lazar 				dev_dbg(dev, "ch[%u]: was configured to use VREF1", i);
1061*bf394cc8SAriana Lazar 				dev_dbg(dev,
1062*bf394cc8SAriana Lazar 					"ch[%u]: reference voltage set to internal band gap", i);
1063*bf394cc8SAriana Lazar 				break;
1064*bf394cc8SAriana Lazar 			}
1065*bf394cc8SAriana Lazar 			if ((data->phys_channels < 4 || (data->phys_channels >= 4 && !(i % 2))) &&
1066*bf394cc8SAriana Lazar 			    !data->use_vref) {
1067*bf394cc8SAriana Lazar 				dev_dbg(dev, "ch[%u]: was configured to use VREF", i);
1068*bf394cc8SAriana Lazar 				dev_dbg(dev,
1069*bf394cc8SAriana Lazar 					"ch[%u]: reference voltage set to internal band gap", i);
1070*bf394cc8SAriana Lazar 				break;
1071*bf394cc8SAriana Lazar 			}
1072*bf394cc8SAriana Lazar 			break;
1073*bf394cc8SAriana Lazar 		}
1074*bf394cc8SAriana Lazar 
1075*bf394cc8SAriana Lazar 		pd_tmp = (pd_ch >> (2 * i)) & MCP47FEB02_DAC_CTRL_MASK;
1076*bf394cc8SAriana Lazar 		data->chdata[i].powerdown_mode = pd_tmp ? (pd_tmp - 1) : pd_tmp;
1077*bf394cc8SAriana Lazar 		data->chdata[i].powerdown = !!(data->chdata[i].powerdown_mode);
1078*bf394cc8SAriana Lazar 	}
1079*bf394cc8SAriana Lazar 
1080*bf394cc8SAriana Lazar 	return 0;
1081*bf394cc8SAriana Lazar }
1082*bf394cc8SAriana Lazar 
1083*bf394cc8SAriana Lazar static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV,
1084*bf394cc8SAriana Lazar 				     int vref_mV, int vref1_mV)
1085*bf394cc8SAriana Lazar {
1086*bf394cc8SAriana Lazar 	unsigned int i;
1087*bf394cc8SAriana Lazar 
1088*bf394cc8SAriana Lazar 	for_each_set_bit(i, &data->active_channels_mask, data->phys_channels) {
1089*bf394cc8SAriana Lazar 		struct device *dev = regmap_get_device(data->regmap);
1090*bf394cc8SAriana Lazar 		int ret;
1091*bf394cc8SAriana Lazar 
1092*bf394cc8SAriana Lazar 		ret = mcp47feb02_init_scales_avail(data, vdd_mV, vref_mV, vref1_mV);
1093*bf394cc8SAriana Lazar 		if (ret)
1094*bf394cc8SAriana Lazar 			return dev_err_probe(dev, ret, "failed to init scales for ch %u\n", i);
1095*bf394cc8SAriana Lazar 	}
1096*bf394cc8SAriana Lazar 
1097*bf394cc8SAriana Lazar 	return 0;
1098*bf394cc8SAriana Lazar }
1099*bf394cc8SAriana Lazar 
1100*bf394cc8SAriana Lazar static int mcp47feb02_probe(struct i2c_client *client)
1101*bf394cc8SAriana Lazar {
1102*bf394cc8SAriana Lazar 	const struct mcp47feb02_features *chip_features;
1103*bf394cc8SAriana Lazar 	struct device *dev = &client->dev;
1104*bf394cc8SAriana Lazar 	struct mcp47feb02_data *data;
1105*bf394cc8SAriana Lazar 	struct iio_dev *indio_dev;
1106*bf394cc8SAriana Lazar 	int vref1_mV = 0;
1107*bf394cc8SAriana Lazar 	int vref_mV = 0;
1108*bf394cc8SAriana Lazar 	int vdd_mV;
1109*bf394cc8SAriana Lazar 	int ret;
1110*bf394cc8SAriana Lazar 
1111*bf394cc8SAriana Lazar 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
1112*bf394cc8SAriana Lazar 	if (!indio_dev)
1113*bf394cc8SAriana Lazar 		return -ENOMEM;
1114*bf394cc8SAriana Lazar 
1115*bf394cc8SAriana Lazar 	data = iio_priv(indio_dev);
1116*bf394cc8SAriana Lazar 	chip_features = i2c_get_match_data(client);
1117*bf394cc8SAriana Lazar 	if (!chip_features)
1118*bf394cc8SAriana Lazar 		return -EINVAL;
1119*bf394cc8SAriana Lazar 
1120*bf394cc8SAriana Lazar 	data->chip_features = chip_features;
1121*bf394cc8SAriana Lazar 
1122*bf394cc8SAriana Lazar 	if (chip_features->have_eeprom) {
1123*bf394cc8SAriana Lazar 		data->regmap = devm_regmap_init_i2c(client, &mcp47feb02_regmap_config);
1124*bf394cc8SAriana Lazar 		indio_dev->info = &mcp47feb02_info;
1125*bf394cc8SAriana Lazar 	} else {
1126*bf394cc8SAriana Lazar 		data->regmap = devm_regmap_init_i2c(client, &mcp47fvb02_regmap_config);
1127*bf394cc8SAriana Lazar 		indio_dev->info = &mcp47fvb02_info;
1128*bf394cc8SAriana Lazar 	}
1129*bf394cc8SAriana Lazar 	if (IS_ERR(data->regmap))
1130*bf394cc8SAriana Lazar 		return dev_err_probe(dev, PTR_ERR(data->regmap), "Error initializing i2c regmap\n");
1131*bf394cc8SAriana Lazar 
1132*bf394cc8SAriana Lazar 	indio_dev->name = chip_features->name;
1133*bf394cc8SAriana Lazar 
1134*bf394cc8SAriana Lazar 	ret = mcp47feb02_parse_fw(indio_dev, chip_features);
1135*bf394cc8SAriana Lazar 	if (ret)
1136*bf394cc8SAriana Lazar 		return dev_err_probe(dev, ret, "Error parsing firmware data\n");
1137*bf394cc8SAriana Lazar 
1138*bf394cc8SAriana Lazar 	ret = devm_mutex_init(dev, &data->lock);
1139*bf394cc8SAriana Lazar 	if (ret)
1140*bf394cc8SAriana Lazar 		return ret;
1141*bf394cc8SAriana Lazar 
1142*bf394cc8SAriana Lazar 	ret = devm_regulator_get_enable_read_voltage(dev, "vdd");
1143*bf394cc8SAriana Lazar 	if (ret < 0)
1144*bf394cc8SAriana Lazar 		return ret;
1145*bf394cc8SAriana Lazar 
1146*bf394cc8SAriana Lazar 	vdd_mV = ret / MILLI;
1147*bf394cc8SAriana Lazar 
1148*bf394cc8SAriana Lazar 	ret = devm_regulator_get_enable_read_voltage(dev, "vref");
1149*bf394cc8SAriana Lazar 	if (ret > 0) {
1150*bf394cc8SAriana Lazar 		vref_mV = ret / MILLI;
1151*bf394cc8SAriana Lazar 		data->use_vref = true;
1152*bf394cc8SAriana Lazar 	} else {
1153*bf394cc8SAriana Lazar 		dev_dbg(dev, "using internal band gap as voltage reference.\n");
1154*bf394cc8SAriana Lazar 		dev_dbg(dev, "Vref is unavailable.\n");
1155*bf394cc8SAriana Lazar 	}
1156*bf394cc8SAriana Lazar 
1157*bf394cc8SAriana Lazar 	if (chip_features->have_ext_vref1) {
1158*bf394cc8SAriana Lazar 		ret = devm_regulator_get_enable_read_voltage(dev, "vref1");
1159*bf394cc8SAriana Lazar 		if (ret > 0) {
1160*bf394cc8SAriana Lazar 			vref1_mV = ret / MILLI;
1161*bf394cc8SAriana Lazar 			data->use_vref1 = true;
1162*bf394cc8SAriana Lazar 		} else {
1163*bf394cc8SAriana Lazar 			dev_dbg(dev, "using internal band gap as voltage reference 1.\n");
1164*bf394cc8SAriana Lazar 			dev_dbg(dev, "Vref1 is unavailable.\n");
1165*bf394cc8SAriana Lazar 		}
1166*bf394cc8SAriana Lazar 	}
1167*bf394cc8SAriana Lazar 
1168*bf394cc8SAriana Lazar 	ret = mcp47feb02_init_ctrl_regs(data);
1169*bf394cc8SAriana Lazar 	if (ret)
1170*bf394cc8SAriana Lazar 		return dev_err_probe(dev, ret, "Error initialising vref register\n");
1171*bf394cc8SAriana Lazar 
1172*bf394cc8SAriana Lazar 	ret = mcp47feb02_init_ch_scales(data, vdd_mV, vref_mV, vref1_mV);
1173*bf394cc8SAriana Lazar 	if (ret)
1174*bf394cc8SAriana Lazar 		return ret;
1175*bf394cc8SAriana Lazar 
1176*bf394cc8SAriana Lazar 	return devm_iio_device_register(dev, indio_dev);
1177*bf394cc8SAriana Lazar }
1178*bf394cc8SAriana Lazar 
1179*bf394cc8SAriana Lazar static const struct i2c_device_id mcp47feb02_id[] = {
1180*bf394cc8SAriana Lazar 	{ "mcp47feb01", (kernel_ulong_t)&mcp47feb01_chip_features },
1181*bf394cc8SAriana Lazar 	{ "mcp47feb02", (kernel_ulong_t)&mcp47feb02_chip_features },
1182*bf394cc8SAriana Lazar 	{ "mcp47feb04", (kernel_ulong_t)&mcp47feb04_chip_features },
1183*bf394cc8SAriana Lazar 	{ "mcp47feb08", (kernel_ulong_t)&mcp47feb08_chip_features },
1184*bf394cc8SAriana Lazar 	{ "mcp47feb11", (kernel_ulong_t)&mcp47feb11_chip_features },
1185*bf394cc8SAriana Lazar 	{ "mcp47feb12", (kernel_ulong_t)&mcp47feb12_chip_features },
1186*bf394cc8SAriana Lazar 	{ "mcp47feb14", (kernel_ulong_t)&mcp47feb14_chip_features },
1187*bf394cc8SAriana Lazar 	{ "mcp47feb18", (kernel_ulong_t)&mcp47feb18_chip_features },
1188*bf394cc8SAriana Lazar 	{ "mcp47feb21", (kernel_ulong_t)&mcp47feb21_chip_features },
1189*bf394cc8SAriana Lazar 	{ "mcp47feb22", (kernel_ulong_t)&mcp47feb22_chip_features },
1190*bf394cc8SAriana Lazar 	{ "mcp47feb24", (kernel_ulong_t)&mcp47feb24_chip_features },
1191*bf394cc8SAriana Lazar 	{ "mcp47feb28", (kernel_ulong_t)&mcp47feb28_chip_features },
1192*bf394cc8SAriana Lazar 	{ "mcp47fvb01", (kernel_ulong_t)&mcp47fvb01_chip_features },
1193*bf394cc8SAriana Lazar 	{ "mcp47fvb02", (kernel_ulong_t)&mcp47fvb02_chip_features },
1194*bf394cc8SAriana Lazar 	{ "mcp47fvb04", (kernel_ulong_t)&mcp47fvb04_chip_features },
1195*bf394cc8SAriana Lazar 	{ "mcp47fvb08", (kernel_ulong_t)&mcp47fvb08_chip_features },
1196*bf394cc8SAriana Lazar 	{ "mcp47fvb11", (kernel_ulong_t)&mcp47fvb11_chip_features },
1197*bf394cc8SAriana Lazar 	{ "mcp47fvb12", (kernel_ulong_t)&mcp47fvb12_chip_features },
1198*bf394cc8SAriana Lazar 	{ "mcp47fvb14", (kernel_ulong_t)&mcp47fvb14_chip_features },
1199*bf394cc8SAriana Lazar 	{ "mcp47fvb18", (kernel_ulong_t)&mcp47fvb18_chip_features },
1200*bf394cc8SAriana Lazar 	{ "mcp47fvb21", (kernel_ulong_t)&mcp47fvb21_chip_features },
1201*bf394cc8SAriana Lazar 	{ "mcp47fvb22", (kernel_ulong_t)&mcp47fvb22_chip_features },
1202*bf394cc8SAriana Lazar 	{ "mcp47fvb24", (kernel_ulong_t)&mcp47fvb24_chip_features },
1203*bf394cc8SAriana Lazar 	{ "mcp47fvb28", (kernel_ulong_t)&mcp47fvb28_chip_features },
1204*bf394cc8SAriana Lazar 	{ }
1205*bf394cc8SAriana Lazar };
1206*bf394cc8SAriana Lazar MODULE_DEVICE_TABLE(i2c, mcp47feb02_id);
1207*bf394cc8SAriana Lazar 
1208*bf394cc8SAriana Lazar static const struct of_device_id mcp47feb02_of_match[] = {
1209*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb01", .data = &mcp47feb01_chip_features },
1210*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb02", .data = &mcp47feb02_chip_features },
1211*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb04", .data = &mcp47feb04_chip_features },
1212*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb08", .data = &mcp47feb08_chip_features },
1213*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb11", .data = &mcp47feb11_chip_features },
1214*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb12", .data = &mcp47feb12_chip_features },
1215*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb14", .data = &mcp47feb14_chip_features },
1216*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb18", .data = &mcp47feb18_chip_features },
1217*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb21", .data = &mcp47feb21_chip_features },
1218*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb22", .data = &mcp47feb22_chip_features },
1219*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb24", .data = &mcp47feb24_chip_features },
1220*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47feb28", .data = &mcp47feb28_chip_features },
1221*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb01", .data = &mcp47fvb01_chip_features },
1222*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb02", .data = &mcp47fvb02_chip_features },
1223*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb04", .data = &mcp47fvb04_chip_features },
1224*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb08", .data = &mcp47fvb08_chip_features },
1225*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb11", .data = &mcp47fvb11_chip_features },
1226*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb12", .data = &mcp47fvb12_chip_features },
1227*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb14",	.data = &mcp47fvb14_chip_features },
1228*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb18", .data = &mcp47fvb18_chip_features },
1229*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb21", .data = &mcp47fvb21_chip_features },
1230*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb22", .data = &mcp47fvb22_chip_features },
1231*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb24", .data = &mcp47fvb24_chip_features },
1232*bf394cc8SAriana Lazar 	{ .compatible = "microchip,mcp47fvb28", .data = &mcp47fvb28_chip_features },
1233*bf394cc8SAriana Lazar 	{ }
1234*bf394cc8SAriana Lazar };
1235*bf394cc8SAriana Lazar MODULE_DEVICE_TABLE(of, mcp47feb02_of_match);
1236*bf394cc8SAriana Lazar 
1237*bf394cc8SAriana Lazar static struct i2c_driver mcp47feb02_driver = {
1238*bf394cc8SAriana Lazar 	.driver = {
1239*bf394cc8SAriana Lazar 		.name	= "mcp47feb02",
1240*bf394cc8SAriana Lazar 		.of_match_table = mcp47feb02_of_match,
1241*bf394cc8SAriana Lazar 		.pm	= pm_sleep_ptr(&mcp47feb02_pm_ops),
1242*bf394cc8SAriana Lazar 	},
1243*bf394cc8SAriana Lazar 	.probe		= mcp47feb02_probe,
1244*bf394cc8SAriana Lazar 	.id_table	= mcp47feb02_id,
1245*bf394cc8SAriana Lazar };
1246*bf394cc8SAriana Lazar module_i2c_driver(mcp47feb02_driver);
1247*bf394cc8SAriana Lazar 
1248*bf394cc8SAriana Lazar MODULE_AUTHOR("Ariana Lazar <ariana.lazar@microchip.com>");
1249*bf394cc8SAriana Lazar MODULE_DESCRIPTION("IIO driver for MCP47FEB02 Multi-Channel DAC with I2C interface");
1250*bf394cc8SAriana Lazar MODULE_LICENSE("GPL");
1251