xref: /linux/drivers/hwmon/chipcap2.c (revision 3af350929e752fe72f0457033d448bff9aac695a)
1*3af35092SJavier Carrasco // SPDX-License-Identifier: GPL-2.0+
2*3af35092SJavier Carrasco /*
3*3af35092SJavier Carrasco  * cc2.c - Support for the Amphenol ChipCap 2 relative humidity, temperature sensor
4*3af35092SJavier Carrasco  *
5*3af35092SJavier Carrasco  * Part numbers supported:
6*3af35092SJavier Carrasco  * CC2D23, CC2D23S, CC2D25, CC2D25S, CC2D33, CC2D33S, CC2D35, CC2D35S
7*3af35092SJavier Carrasco  *
8*3af35092SJavier Carrasco  * Author: Javier Carrasco <javier.carrasco.cruz@gmail.com>
9*3af35092SJavier Carrasco  *
10*3af35092SJavier Carrasco  * Datasheet and application notes:
11*3af35092SJavier Carrasco  * https://www.amphenol-sensors.com/en/telaire/humidity/527-humidity-sensors/3095-chipcap-2
12*3af35092SJavier Carrasco  */
13*3af35092SJavier Carrasco 
14*3af35092SJavier Carrasco #include <linux/bitfield.h>
15*3af35092SJavier Carrasco #include <linux/bits.h>
16*3af35092SJavier Carrasco #include <linux/completion.h>
17*3af35092SJavier Carrasco #include <linux/delay.h>
18*3af35092SJavier Carrasco #include <linux/hwmon.h>
19*3af35092SJavier Carrasco #include <linux/i2c.h>
20*3af35092SJavier Carrasco #include <linux/interrupt.h>
21*3af35092SJavier Carrasco #include <linux/irq.h>
22*3af35092SJavier Carrasco #include <linux/module.h>
23*3af35092SJavier Carrasco #include <linux/regulator/consumer.h>
24*3af35092SJavier Carrasco 
25*3af35092SJavier Carrasco #define CC2_START_CM			0xA0
26*3af35092SJavier Carrasco #define CC2_START_NOM			0x80
27*3af35092SJavier Carrasco #define CC2_R_ALARM_H_ON		0x18
28*3af35092SJavier Carrasco #define CC2_R_ALARM_H_OFF		0x19
29*3af35092SJavier Carrasco #define CC2_R_ALARM_L_ON		0x1A
30*3af35092SJavier Carrasco #define CC2_R_ALARM_L_OFF		0x1B
31*3af35092SJavier Carrasco #define CC2_RW_OFFSET			0x40
32*3af35092SJavier Carrasco #define CC2_W_ALARM_H_ON		(CC2_R_ALARM_H_ON + CC2_RW_OFFSET)
33*3af35092SJavier Carrasco #define CC2_W_ALARM_H_OFF		(CC2_R_ALARM_H_OFF + CC2_RW_OFFSET)
34*3af35092SJavier Carrasco #define CC2_W_ALARM_L_ON		(CC2_R_ALARM_L_ON + CC2_RW_OFFSET)
35*3af35092SJavier Carrasco #define CC2_W_ALARM_L_OFF		(CC2_R_ALARM_L_OFF + CC2_RW_OFFSET)
36*3af35092SJavier Carrasco 
37*3af35092SJavier Carrasco #define CC2_STATUS_FIELD		GENMASK(7, 6)
38*3af35092SJavier Carrasco #define CC2_STATUS_VALID_DATA		0x00
39*3af35092SJavier Carrasco #define CC2_STATUS_STALE_DATA		0x01
40*3af35092SJavier Carrasco #define CC2_STATUS_CMD_MODE		0x02
41*3af35092SJavier Carrasco 
42*3af35092SJavier Carrasco #define CC2_RESPONSE_FIELD		GENMASK(1, 0)
43*3af35092SJavier Carrasco #define CC2_RESPONSE_BUSY		0x00
44*3af35092SJavier Carrasco #define CC2_RESPONSE_ACK		0x01
45*3af35092SJavier Carrasco #define CC2_RESPONSE_NACK		0x02
46*3af35092SJavier Carrasco 
47*3af35092SJavier Carrasco #define CC2_ERR_CORR_EEPROM		BIT(2)
48*3af35092SJavier Carrasco #define CC2_ERR_UNCORR_EEPROM		BIT(3)
49*3af35092SJavier Carrasco #define CC2_ERR_RAM_PARITY		BIT(4)
50*3af35092SJavier Carrasco #define CC2_ERR_CONFIG_LOAD		BIT(5)
51*3af35092SJavier Carrasco 
52*3af35092SJavier Carrasco #define CC2_EEPROM_SIZE			10
53*3af35092SJavier Carrasco #define CC2_EEPROM_DATA_LEN		3
54*3af35092SJavier Carrasco #define CC2_MEASUREMENT_DATA_LEN	4
55*3af35092SJavier Carrasco 
56*3af35092SJavier Carrasco #define CC2_RH_DATA_FIELD		GENMASK(13, 0)
57*3af35092SJavier Carrasco 
58*3af35092SJavier Carrasco /* ensure clean off -> on transitions */
59*3af35092SJavier Carrasco #define CC2_POWER_CYCLE_MS		80
60*3af35092SJavier Carrasco 
61*3af35092SJavier Carrasco #define CC2_STARTUP_TO_DATA_MS		55
62*3af35092SJavier Carrasco #define CC2_RESP_START_CM_US		100
63*3af35092SJavier Carrasco #define CC2_RESP_EEPROM_R_US		100
64*3af35092SJavier Carrasco #define CC2_RESP_EEPROM_W_MS		12
65*3af35092SJavier Carrasco #define CC2_STARTUP_TIME_US		1250
66*3af35092SJavier Carrasco 
67*3af35092SJavier Carrasco #define CC2_RH_MAX			(100 * 1000U)
68*3af35092SJavier Carrasco 
69*3af35092SJavier Carrasco #define CC2_CM_RETRIES			5
70*3af35092SJavier Carrasco 
71*3af35092SJavier Carrasco struct cc2_rh_alarm_info {
72*3af35092SJavier Carrasco 	bool low_alarm;
73*3af35092SJavier Carrasco 	bool high_alarm;
74*3af35092SJavier Carrasco 	bool low_alarm_visible;
75*3af35092SJavier Carrasco 	bool high_alarm_visible;
76*3af35092SJavier Carrasco };
77*3af35092SJavier Carrasco 
78*3af35092SJavier Carrasco struct cc2_data {
79*3af35092SJavier Carrasco 	struct cc2_rh_alarm_info rh_alarm;
80*3af35092SJavier Carrasco 	struct completion complete;
81*3af35092SJavier Carrasco 	struct device *hwmon;
82*3af35092SJavier Carrasco 	struct i2c_client *client;
83*3af35092SJavier Carrasco 	struct mutex dev_access_lock; /* device access lock */
84*3af35092SJavier Carrasco 	struct regulator *regulator;
85*3af35092SJavier Carrasco 	const char *name;
86*3af35092SJavier Carrasco 	int irq_ready;
87*3af35092SJavier Carrasco 	int irq_low;
88*3af35092SJavier Carrasco 	int irq_high;
89*3af35092SJavier Carrasco 	bool process_irqs;
90*3af35092SJavier Carrasco };
91*3af35092SJavier Carrasco 
92*3af35092SJavier Carrasco enum cc2_chan_addr {
93*3af35092SJavier Carrasco 	CC2_CHAN_TEMP = 0,
94*3af35092SJavier Carrasco 	CC2_CHAN_HUMIDITY,
95*3af35092SJavier Carrasco };
96*3af35092SJavier Carrasco 
97*3af35092SJavier Carrasco /* %RH as a per cent mille from a register value */
98*3af35092SJavier Carrasco static long cc2_rh_convert(u16 data)
99*3af35092SJavier Carrasco {
100*3af35092SJavier Carrasco 	unsigned long tmp = (data & CC2_RH_DATA_FIELD) * CC2_RH_MAX;
101*3af35092SJavier Carrasco 
102*3af35092SJavier Carrasco 	return tmp / ((1 << 14) - 1);
103*3af35092SJavier Carrasco }
104*3af35092SJavier Carrasco 
105*3af35092SJavier Carrasco /* convert %RH to a register value */
106*3af35092SJavier Carrasco static u16 cc2_rh_to_reg(long data)
107*3af35092SJavier Carrasco {
108*3af35092SJavier Carrasco 	return data * ((1 << 14) - 1) / CC2_RH_MAX;
109*3af35092SJavier Carrasco }
110*3af35092SJavier Carrasco 
111*3af35092SJavier Carrasco /* temperature in milli degrees celsius from a register value */
112*3af35092SJavier Carrasco static long cc2_temp_convert(u16 data)
113*3af35092SJavier Carrasco {
114*3af35092SJavier Carrasco 	unsigned long tmp = ((data >> 2) * 165 * 1000U) / ((1 << 14) - 1);
115*3af35092SJavier Carrasco 
116*3af35092SJavier Carrasco 	return tmp - 40 * 1000U;
117*3af35092SJavier Carrasco }
118*3af35092SJavier Carrasco 
119*3af35092SJavier Carrasco static int cc2_enable(struct cc2_data *data)
120*3af35092SJavier Carrasco {
121*3af35092SJavier Carrasco 	int ret;
122*3af35092SJavier Carrasco 
123*3af35092SJavier Carrasco 	/* exclusive regulator, check in case a disable failed */
124*3af35092SJavier Carrasco 	if (regulator_is_enabled(data->regulator))
125*3af35092SJavier Carrasco 		return 0;
126*3af35092SJavier Carrasco 
127*3af35092SJavier Carrasco 	/* clear any pending completion */
128*3af35092SJavier Carrasco 	try_wait_for_completion(&data->complete);
129*3af35092SJavier Carrasco 
130*3af35092SJavier Carrasco 	ret = regulator_enable(data->regulator);
131*3af35092SJavier Carrasco 	if (ret < 0)
132*3af35092SJavier Carrasco 		return ret;
133*3af35092SJavier Carrasco 
134*3af35092SJavier Carrasco 	usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
135*3af35092SJavier Carrasco 
136*3af35092SJavier Carrasco 	data->process_irqs = true;
137*3af35092SJavier Carrasco 
138*3af35092SJavier Carrasco 	return 0;
139*3af35092SJavier Carrasco }
140*3af35092SJavier Carrasco 
141*3af35092SJavier Carrasco static void cc2_disable(struct cc2_data *data)
142*3af35092SJavier Carrasco {
143*3af35092SJavier Carrasco 	int err;
144*3af35092SJavier Carrasco 
145*3af35092SJavier Carrasco 	/* ignore alarms triggered by voltage toggling when powering up */
146*3af35092SJavier Carrasco 	data->process_irqs = false;
147*3af35092SJavier Carrasco 
148*3af35092SJavier Carrasco 	/* exclusive regulator, check in case an enable failed */
149*3af35092SJavier Carrasco 	if (regulator_is_enabled(data->regulator)) {
150*3af35092SJavier Carrasco 		err = regulator_disable(data->regulator);
151*3af35092SJavier Carrasco 		if (err)
152*3af35092SJavier Carrasco 			dev_dbg(&data->client->dev, "Failed to disable device");
153*3af35092SJavier Carrasco 	}
154*3af35092SJavier Carrasco }
155*3af35092SJavier Carrasco 
156*3af35092SJavier Carrasco static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
157*3af35092SJavier Carrasco {
158*3af35092SJavier Carrasco 	int resp;
159*3af35092SJavier Carrasco 
160*3af35092SJavier Carrasco 	if (FIELD_GET(CC2_STATUS_FIELD, status) != CC2_STATUS_CMD_MODE) {
161*3af35092SJavier Carrasco 		dev_dbg(dev, "Command sent out of command window\n");
162*3af35092SJavier Carrasco 		return -ETIMEDOUT;
163*3af35092SJavier Carrasco 	}
164*3af35092SJavier Carrasco 
165*3af35092SJavier Carrasco 	resp = FIELD_GET(CC2_RESPONSE_FIELD, status);
166*3af35092SJavier Carrasco 	switch (resp) {
167*3af35092SJavier Carrasco 	case CC2_RESPONSE_ACK:
168*3af35092SJavier Carrasco 		return 0;
169*3af35092SJavier Carrasco 	case CC2_RESPONSE_BUSY:
170*3af35092SJavier Carrasco 		return -EBUSY;
171*3af35092SJavier Carrasco 	case CC2_RESPONSE_NACK:
172*3af35092SJavier Carrasco 		if (resp & CC2_ERR_CORR_EEPROM)
173*3af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: corrected EEPROM\n");
174*3af35092SJavier Carrasco 		if (resp & CC2_ERR_UNCORR_EEPROM)
175*3af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: uncorrected EEPROM\n");
176*3af35092SJavier Carrasco 		if (resp & CC2_ERR_RAM_PARITY)
177*3af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: RAM parity\n");
178*3af35092SJavier Carrasco 		if (resp & CC2_ERR_RAM_PARITY)
179*3af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: configuration error\n");
180*3af35092SJavier Carrasco 		return -ENODATA;
181*3af35092SJavier Carrasco 	default:
182*3af35092SJavier Carrasco 		dev_dbg(dev, "Unknown command reply\n");
183*3af35092SJavier Carrasco 		return -EINVAL;
184*3af35092SJavier Carrasco 	}
185*3af35092SJavier Carrasco }
186*3af35092SJavier Carrasco 
187*3af35092SJavier Carrasco static int cc2_read_command_status(struct i2c_client *client)
188*3af35092SJavier Carrasco {
189*3af35092SJavier Carrasco 	u8 status;
190*3af35092SJavier Carrasco 	int ret;
191*3af35092SJavier Carrasco 
192*3af35092SJavier Carrasco 	ret = i2c_master_recv(client, &status, 1);
193*3af35092SJavier Carrasco 	if (ret != 1) {
194*3af35092SJavier Carrasco 		ret = ret < 0 ? ret : -EIO;
195*3af35092SJavier Carrasco 		return ret;
196*3af35092SJavier Carrasco 	}
197*3af35092SJavier Carrasco 
198*3af35092SJavier Carrasco 	return cc2_cmd_response_diagnostic(&client->dev, status);
199*3af35092SJavier Carrasco }
200*3af35092SJavier Carrasco 
201*3af35092SJavier Carrasco /*
202*3af35092SJavier Carrasco  * The command mode is only accessible after sending the START_CM command in the
203*3af35092SJavier Carrasco  * first 10 ms after power-up. Only in case the command window is missed,
204*3af35092SJavier Carrasco  * CC2_CM_RETRIES retries are attempted before giving up and returning an error.
205*3af35092SJavier Carrasco  */
206*3af35092SJavier Carrasco static int cc2_command_mode_start(struct cc2_data *data)
207*3af35092SJavier Carrasco {
208*3af35092SJavier Carrasco 	unsigned long timeout;
209*3af35092SJavier Carrasco 	int i, ret;
210*3af35092SJavier Carrasco 
211*3af35092SJavier Carrasco 	for (i = 0; i < CC2_CM_RETRIES; i++) {
212*3af35092SJavier Carrasco 		ret = cc2_enable(data);
213*3af35092SJavier Carrasco 		if (ret < 0)
214*3af35092SJavier Carrasco 			return ret;
215*3af35092SJavier Carrasco 
216*3af35092SJavier Carrasco 		ret = i2c_smbus_write_word_data(data->client, CC2_START_CM, 0);
217*3af35092SJavier Carrasco 		if (ret < 0)
218*3af35092SJavier Carrasco 			return ret;
219*3af35092SJavier Carrasco 
220*3af35092SJavier Carrasco 		if (data->irq_ready > 0) {
221*3af35092SJavier Carrasco 			timeout = usecs_to_jiffies(2 * CC2_RESP_START_CM_US);
222*3af35092SJavier Carrasco 			ret = wait_for_completion_timeout(&data->complete,
223*3af35092SJavier Carrasco 							  timeout);
224*3af35092SJavier Carrasco 			if (!ret)
225*3af35092SJavier Carrasco 				return -ETIMEDOUT;
226*3af35092SJavier Carrasco 		} else {
227*3af35092SJavier Carrasco 			usleep_range(CC2_RESP_START_CM_US,
228*3af35092SJavier Carrasco 				     2 * CC2_RESP_START_CM_US);
229*3af35092SJavier Carrasco 		}
230*3af35092SJavier Carrasco 		ret = cc2_read_command_status(data->client);
231*3af35092SJavier Carrasco 		if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES)
232*3af35092SJavier Carrasco 			break;
233*3af35092SJavier Carrasco 
234*3af35092SJavier Carrasco 		/* command window missed, prepare for a retry */
235*3af35092SJavier Carrasco 		cc2_disable(data);
236*3af35092SJavier Carrasco 		msleep(CC2_POWER_CYCLE_MS);
237*3af35092SJavier Carrasco 	}
238*3af35092SJavier Carrasco 
239*3af35092SJavier Carrasco 	return ret;
240*3af35092SJavier Carrasco }
241*3af35092SJavier Carrasco 
242*3af35092SJavier Carrasco /* Sending a Start_NOM command finishes the command mode immediately with no
243*3af35092SJavier Carrasco  * reply and the device enters normal operation mode
244*3af35092SJavier Carrasco  */
245*3af35092SJavier Carrasco static int cc2_command_mode_finish(struct cc2_data *data)
246*3af35092SJavier Carrasco {
247*3af35092SJavier Carrasco 	int ret;
248*3af35092SJavier Carrasco 
249*3af35092SJavier Carrasco 	ret = i2c_smbus_write_word_data(data->client, CC2_START_NOM, 0);
250*3af35092SJavier Carrasco 	if (ret < 0)
251*3af35092SJavier Carrasco 		return ret;
252*3af35092SJavier Carrasco 
253*3af35092SJavier Carrasco 	return 0;
254*3af35092SJavier Carrasco }
255*3af35092SJavier Carrasco 
256*3af35092SJavier Carrasco static int cc2_write_reg(struct cc2_data *data, u8 reg, u16 val)
257*3af35092SJavier Carrasco {
258*3af35092SJavier Carrasco 	unsigned long timeout;
259*3af35092SJavier Carrasco 	int ret;
260*3af35092SJavier Carrasco 
261*3af35092SJavier Carrasco 	ret = cc2_command_mode_start(data);
262*3af35092SJavier Carrasco 	if (ret < 0)
263*3af35092SJavier Carrasco 		goto disable;
264*3af35092SJavier Carrasco 
265*3af35092SJavier Carrasco 	cpu_to_be16s(&val);
266*3af35092SJavier Carrasco 	ret = i2c_smbus_write_word_data(data->client, reg, val);
267*3af35092SJavier Carrasco 	if (ret < 0)
268*3af35092SJavier Carrasco 		goto disable;
269*3af35092SJavier Carrasco 
270*3af35092SJavier Carrasco 	if (data->irq_ready > 0) {
271*3af35092SJavier Carrasco 		timeout = msecs_to_jiffies(2 * CC2_RESP_EEPROM_W_MS);
272*3af35092SJavier Carrasco 		ret = wait_for_completion_timeout(&data->complete, timeout);
273*3af35092SJavier Carrasco 		if (!ret) {
274*3af35092SJavier Carrasco 			ret = -ETIMEDOUT;
275*3af35092SJavier Carrasco 			goto disable;
276*3af35092SJavier Carrasco 		}
277*3af35092SJavier Carrasco 	} else {
278*3af35092SJavier Carrasco 		msleep(CC2_RESP_EEPROM_W_MS);
279*3af35092SJavier Carrasco 	}
280*3af35092SJavier Carrasco 
281*3af35092SJavier Carrasco 	ret = cc2_read_command_status(data->client);
282*3af35092SJavier Carrasco 
283*3af35092SJavier Carrasco disable:
284*3af35092SJavier Carrasco 	cc2_disable(data);
285*3af35092SJavier Carrasco 
286*3af35092SJavier Carrasco 	return ret;
287*3af35092SJavier Carrasco }
288*3af35092SJavier Carrasco 
289*3af35092SJavier Carrasco static int cc2_read_reg(struct cc2_data *data, u8 reg, u16 *val)
290*3af35092SJavier Carrasco {
291*3af35092SJavier Carrasco 	u8 buf[CC2_EEPROM_DATA_LEN];
292*3af35092SJavier Carrasco 	unsigned long timeout;
293*3af35092SJavier Carrasco 	int ret;
294*3af35092SJavier Carrasco 
295*3af35092SJavier Carrasco 	ret = cc2_command_mode_start(data);
296*3af35092SJavier Carrasco 	if (ret < 0)
297*3af35092SJavier Carrasco 		return ret;
298*3af35092SJavier Carrasco 
299*3af35092SJavier Carrasco 	ret = i2c_smbus_write_word_data(data->client, reg, 0);
300*3af35092SJavier Carrasco 	if (ret < 0)
301*3af35092SJavier Carrasco 		return ret;
302*3af35092SJavier Carrasco 
303*3af35092SJavier Carrasco 	if (data->irq_ready > 0) {
304*3af35092SJavier Carrasco 		timeout = usecs_to_jiffies(2 * CC2_RESP_EEPROM_R_US);
305*3af35092SJavier Carrasco 		ret = wait_for_completion_timeout(&data->complete, timeout);
306*3af35092SJavier Carrasco 		if (!ret)
307*3af35092SJavier Carrasco 			return -ETIMEDOUT;
308*3af35092SJavier Carrasco 
309*3af35092SJavier Carrasco 	} else {
310*3af35092SJavier Carrasco 		usleep_range(CC2_RESP_EEPROM_R_US, CC2_RESP_EEPROM_R_US + 10);
311*3af35092SJavier Carrasco 	}
312*3af35092SJavier Carrasco 	ret = i2c_master_recv(data->client, buf, CC2_EEPROM_DATA_LEN);
313*3af35092SJavier Carrasco 	if (ret != CC2_EEPROM_DATA_LEN)
314*3af35092SJavier Carrasco 		return ret < 0 ? ret : -EIO;
315*3af35092SJavier Carrasco 
316*3af35092SJavier Carrasco 	*val = be16_to_cpup((__be16 *)&buf[1]);
317*3af35092SJavier Carrasco 
318*3af35092SJavier Carrasco 	return cc2_read_command_status(data->client);
319*3af35092SJavier Carrasco }
320*3af35092SJavier Carrasco 
321*3af35092SJavier Carrasco static int cc2_get_reg_val(struct cc2_data *data, u8 reg, long *val)
322*3af35092SJavier Carrasco {
323*3af35092SJavier Carrasco 	u16 reg_val;
324*3af35092SJavier Carrasco 	int ret;
325*3af35092SJavier Carrasco 
326*3af35092SJavier Carrasco 	ret = cc2_read_reg(data, reg, &reg_val);
327*3af35092SJavier Carrasco 	*val = cc2_rh_convert(reg_val);
328*3af35092SJavier Carrasco 	cc2_disable(data);
329*3af35092SJavier Carrasco 
330*3af35092SJavier Carrasco 	return ret;
331*3af35092SJavier Carrasco }
332*3af35092SJavier Carrasco 
333*3af35092SJavier Carrasco static int cc2_data_fetch(struct i2c_client *client,
334*3af35092SJavier Carrasco 			  enum hwmon_sensor_types type, long *val)
335*3af35092SJavier Carrasco {
336*3af35092SJavier Carrasco 	u8 data[CC2_MEASUREMENT_DATA_LEN];
337*3af35092SJavier Carrasco 	u8 status;
338*3af35092SJavier Carrasco 	int ret;
339*3af35092SJavier Carrasco 
340*3af35092SJavier Carrasco 	ret = i2c_master_recv(client, data, CC2_MEASUREMENT_DATA_LEN);
341*3af35092SJavier Carrasco 	if (ret != CC2_MEASUREMENT_DATA_LEN) {
342*3af35092SJavier Carrasco 		ret = ret < 0 ? ret : -EIO;
343*3af35092SJavier Carrasco 		return ret;
344*3af35092SJavier Carrasco 	}
345*3af35092SJavier Carrasco 	status = FIELD_GET(CC2_STATUS_FIELD, data[0]);
346*3af35092SJavier Carrasco 	if (status == CC2_STATUS_STALE_DATA)
347*3af35092SJavier Carrasco 		return -EBUSY;
348*3af35092SJavier Carrasco 
349*3af35092SJavier Carrasco 	if (status != CC2_STATUS_VALID_DATA)
350*3af35092SJavier Carrasco 		return -EIO;
351*3af35092SJavier Carrasco 
352*3af35092SJavier Carrasco 	switch (type) {
353*3af35092SJavier Carrasco 	case hwmon_humidity:
354*3af35092SJavier Carrasco 		*val = cc2_rh_convert(be16_to_cpup((__be16 *)&data[0]));
355*3af35092SJavier Carrasco 		break;
356*3af35092SJavier Carrasco 	case hwmon_temp:
357*3af35092SJavier Carrasco 		*val = cc2_temp_convert(be16_to_cpup((__be16 *)&data[2]));
358*3af35092SJavier Carrasco 		break;
359*3af35092SJavier Carrasco 	default:
360*3af35092SJavier Carrasco 		return -EINVAL;
361*3af35092SJavier Carrasco 	}
362*3af35092SJavier Carrasco 
363*3af35092SJavier Carrasco 	return 0;
364*3af35092SJavier Carrasco }
365*3af35092SJavier Carrasco 
366*3af35092SJavier Carrasco static int cc2_read_measurement(struct cc2_data *data,
367*3af35092SJavier Carrasco 				enum hwmon_sensor_types type, long *val)
368*3af35092SJavier Carrasco {
369*3af35092SJavier Carrasco 	unsigned long timeout;
370*3af35092SJavier Carrasco 	int ret;
371*3af35092SJavier Carrasco 
372*3af35092SJavier Carrasco 	if (data->irq_ready > 0) {
373*3af35092SJavier Carrasco 		timeout = msecs_to_jiffies(CC2_STARTUP_TO_DATA_MS * 2);
374*3af35092SJavier Carrasco 		ret = wait_for_completion_timeout(&data->complete, timeout);
375*3af35092SJavier Carrasco 		if (!ret)
376*3af35092SJavier Carrasco 			return -ETIMEDOUT;
377*3af35092SJavier Carrasco 
378*3af35092SJavier Carrasco 	} else {
379*3af35092SJavier Carrasco 		msleep(CC2_STARTUP_TO_DATA_MS);
380*3af35092SJavier Carrasco 	}
381*3af35092SJavier Carrasco 
382*3af35092SJavier Carrasco 	ret = cc2_data_fetch(data->client, type, val);
383*3af35092SJavier Carrasco 
384*3af35092SJavier Carrasco 	return ret;
385*3af35092SJavier Carrasco }
386*3af35092SJavier Carrasco 
387*3af35092SJavier Carrasco /*
388*3af35092SJavier Carrasco  * A measurement requires enabling the device, waiting for the automatic
389*3af35092SJavier Carrasco  * measurement to finish, reading the measurement data and disabling the device
390*3af35092SJavier Carrasco  * again.
391*3af35092SJavier Carrasco  */
392*3af35092SJavier Carrasco static int cc2_measurement(struct cc2_data *data, enum hwmon_sensor_types type,
393*3af35092SJavier Carrasco 			   long *val)
394*3af35092SJavier Carrasco {
395*3af35092SJavier Carrasco 	int ret;
396*3af35092SJavier Carrasco 
397*3af35092SJavier Carrasco 	ret = cc2_enable(data);
398*3af35092SJavier Carrasco 	if (ret)
399*3af35092SJavier Carrasco 		return ret;
400*3af35092SJavier Carrasco 
401*3af35092SJavier Carrasco 	ret = cc2_read_measurement(data, type, val);
402*3af35092SJavier Carrasco 
403*3af35092SJavier Carrasco 	cc2_disable(data);
404*3af35092SJavier Carrasco 
405*3af35092SJavier Carrasco 	return ret;
406*3af35092SJavier Carrasco }
407*3af35092SJavier Carrasco 
408*3af35092SJavier Carrasco /*
409*3af35092SJavier Carrasco  * In order to check alarm status, the corresponding ALARM_OFF (hysteresis)
410*3af35092SJavier Carrasco  * register must be read and a new measurement must be carried out to trigger
411*3af35092SJavier Carrasco  * the alarm signals. Given that the device carries out a measurement after
412*3af35092SJavier Carrasco  * exiting the command mode, there is no need to force two power-up sequences.
413*3af35092SJavier Carrasco  * Instead, a NOM command is sent and the device is disabled after the
414*3af35092SJavier Carrasco  * measurement is read.
415*3af35092SJavier Carrasco  */
416*3af35092SJavier Carrasco static int cc2_read_hyst_and_measure(struct cc2_data *data, u8 reg,
417*3af35092SJavier Carrasco 				     long *hyst, long *measurement)
418*3af35092SJavier Carrasco {
419*3af35092SJavier Carrasco 	u16 reg_val;
420*3af35092SJavier Carrasco 	int ret;
421*3af35092SJavier Carrasco 
422*3af35092SJavier Carrasco 	ret = cc2_read_reg(data, reg, &reg_val);
423*3af35092SJavier Carrasco 	if (ret)
424*3af35092SJavier Carrasco 		goto disable;
425*3af35092SJavier Carrasco 
426*3af35092SJavier Carrasco 	*hyst = cc2_rh_convert(reg_val);
427*3af35092SJavier Carrasco 
428*3af35092SJavier Carrasco 	ret = cc2_command_mode_finish(data);
429*3af35092SJavier Carrasco 	if (ret)
430*3af35092SJavier Carrasco 		goto disable;
431*3af35092SJavier Carrasco 
432*3af35092SJavier Carrasco 	ret = cc2_read_measurement(data, hwmon_humidity, measurement);
433*3af35092SJavier Carrasco 
434*3af35092SJavier Carrasco disable:
435*3af35092SJavier Carrasco 	cc2_disable(data);
436*3af35092SJavier Carrasco 
437*3af35092SJavier Carrasco 	return ret;
438*3af35092SJavier Carrasco }
439*3af35092SJavier Carrasco 
440*3af35092SJavier Carrasco static umode_t cc2_is_visible(const void *data, enum hwmon_sensor_types type,
441*3af35092SJavier Carrasco 			      u32 attr, int channel)
442*3af35092SJavier Carrasco {
443*3af35092SJavier Carrasco 	const struct cc2_data *cc2 = data;
444*3af35092SJavier Carrasco 
445*3af35092SJavier Carrasco 	switch (type) {
446*3af35092SJavier Carrasco 	case hwmon_humidity:
447*3af35092SJavier Carrasco 		switch (attr) {
448*3af35092SJavier Carrasco 		case hwmon_humidity_input:
449*3af35092SJavier Carrasco 			return 0444;
450*3af35092SJavier Carrasco 		case hwmon_humidity_min_alarm:
451*3af35092SJavier Carrasco 			return cc2->rh_alarm.low_alarm_visible ? 0444 : 0;
452*3af35092SJavier Carrasco 		case hwmon_humidity_max_alarm:
453*3af35092SJavier Carrasco 			return cc2->rh_alarm.high_alarm_visible ? 0444 : 0;
454*3af35092SJavier Carrasco 		case hwmon_humidity_min:
455*3af35092SJavier Carrasco 		case hwmon_humidity_min_hyst:
456*3af35092SJavier Carrasco 			return cc2->rh_alarm.low_alarm_visible ? 0644 : 0;
457*3af35092SJavier Carrasco 		case hwmon_humidity_max:
458*3af35092SJavier Carrasco 		case hwmon_humidity_max_hyst:
459*3af35092SJavier Carrasco 			return cc2->rh_alarm.high_alarm_visible ? 0644 : 0;
460*3af35092SJavier Carrasco 		default:
461*3af35092SJavier Carrasco 			return 0;
462*3af35092SJavier Carrasco 		}
463*3af35092SJavier Carrasco 	case hwmon_temp:
464*3af35092SJavier Carrasco 		switch (attr) {
465*3af35092SJavier Carrasco 		case hwmon_temp_input:
466*3af35092SJavier Carrasco 			return 0444;
467*3af35092SJavier Carrasco 		default:
468*3af35092SJavier Carrasco 			return 0;
469*3af35092SJavier Carrasco 		}
470*3af35092SJavier Carrasco 	default:
471*3af35092SJavier Carrasco 		break;
472*3af35092SJavier Carrasco 	}
473*3af35092SJavier Carrasco 
474*3af35092SJavier Carrasco 	return 0;
475*3af35092SJavier Carrasco }
476*3af35092SJavier Carrasco 
477*3af35092SJavier Carrasco static irqreturn_t cc2_ready_interrupt(int irq, void *data)
478*3af35092SJavier Carrasco {
479*3af35092SJavier Carrasco 	struct cc2_data *cc2 = data;
480*3af35092SJavier Carrasco 
481*3af35092SJavier Carrasco 	if (cc2->process_irqs)
482*3af35092SJavier Carrasco 		complete(&cc2->complete);
483*3af35092SJavier Carrasco 
484*3af35092SJavier Carrasco 	return IRQ_HANDLED;
485*3af35092SJavier Carrasco }
486*3af35092SJavier Carrasco 
487*3af35092SJavier Carrasco static irqreturn_t cc2_low_interrupt(int irq, void *data)
488*3af35092SJavier Carrasco {
489*3af35092SJavier Carrasco 	struct cc2_data *cc2 = data;
490*3af35092SJavier Carrasco 
491*3af35092SJavier Carrasco 	if (cc2->process_irqs) {
492*3af35092SJavier Carrasco 		hwmon_notify_event(cc2->hwmon, hwmon_humidity,
493*3af35092SJavier Carrasco 				   hwmon_humidity_min_alarm, CC2_CHAN_HUMIDITY);
494*3af35092SJavier Carrasco 		cc2->rh_alarm.low_alarm = true;
495*3af35092SJavier Carrasco 	}
496*3af35092SJavier Carrasco 
497*3af35092SJavier Carrasco 	return IRQ_HANDLED;
498*3af35092SJavier Carrasco }
499*3af35092SJavier Carrasco 
500*3af35092SJavier Carrasco static irqreturn_t cc2_high_interrupt(int irq, void *data)
501*3af35092SJavier Carrasco {
502*3af35092SJavier Carrasco 	struct cc2_data *cc2 = data;
503*3af35092SJavier Carrasco 
504*3af35092SJavier Carrasco 	if (cc2->process_irqs) {
505*3af35092SJavier Carrasco 		hwmon_notify_event(cc2->hwmon, hwmon_humidity,
506*3af35092SJavier Carrasco 				   hwmon_humidity_max_alarm, CC2_CHAN_HUMIDITY);
507*3af35092SJavier Carrasco 		cc2->rh_alarm.high_alarm = true;
508*3af35092SJavier Carrasco 	}
509*3af35092SJavier Carrasco 
510*3af35092SJavier Carrasco 	return IRQ_HANDLED;
511*3af35092SJavier Carrasco }
512*3af35092SJavier Carrasco 
513*3af35092SJavier Carrasco static int cc2_humidity_min_alarm_status(struct cc2_data *data, long *val)
514*3af35092SJavier Carrasco {
515*3af35092SJavier Carrasco 	long measurement, min_hyst;
516*3af35092SJavier Carrasco 	int ret;
517*3af35092SJavier Carrasco 
518*3af35092SJavier Carrasco 	ret = cc2_read_hyst_and_measure(data, CC2_R_ALARM_L_OFF, &min_hyst,
519*3af35092SJavier Carrasco 					&measurement);
520*3af35092SJavier Carrasco 	if (ret < 0)
521*3af35092SJavier Carrasco 		return ret;
522*3af35092SJavier Carrasco 
523*3af35092SJavier Carrasco 	if (data->rh_alarm.low_alarm) {
524*3af35092SJavier Carrasco 		*val = (measurement < min_hyst) ? 1 : 0;
525*3af35092SJavier Carrasco 		data->rh_alarm.low_alarm = *val;
526*3af35092SJavier Carrasco 	} else {
527*3af35092SJavier Carrasco 		*val = 0;
528*3af35092SJavier Carrasco 	}
529*3af35092SJavier Carrasco 
530*3af35092SJavier Carrasco 	return 0;
531*3af35092SJavier Carrasco }
532*3af35092SJavier Carrasco 
533*3af35092SJavier Carrasco static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val)
534*3af35092SJavier Carrasco {
535*3af35092SJavier Carrasco 	long measurement, max_hyst;
536*3af35092SJavier Carrasco 	int ret;
537*3af35092SJavier Carrasco 
538*3af35092SJavier Carrasco 	ret = cc2_read_hyst_and_measure(data, CC2_R_ALARM_H_OFF, &max_hyst,
539*3af35092SJavier Carrasco 					&measurement);
540*3af35092SJavier Carrasco 	if (ret < 0)
541*3af35092SJavier Carrasco 		return ret;
542*3af35092SJavier Carrasco 
543*3af35092SJavier Carrasco 	if (data->rh_alarm.high_alarm) {
544*3af35092SJavier Carrasco 		*val = (measurement > max_hyst) ? 1 : 0;
545*3af35092SJavier Carrasco 		data->rh_alarm.high_alarm = *val;
546*3af35092SJavier Carrasco 	} else {
547*3af35092SJavier Carrasco 		*val = 0;
548*3af35092SJavier Carrasco 	}
549*3af35092SJavier Carrasco 
550*3af35092SJavier Carrasco 	return 0;
551*3af35092SJavier Carrasco }
552*3af35092SJavier Carrasco 
553*3af35092SJavier Carrasco static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
554*3af35092SJavier Carrasco 		    int channel, long *val)
555*3af35092SJavier Carrasco {
556*3af35092SJavier Carrasco 	struct cc2_data *data = dev_get_drvdata(dev);
557*3af35092SJavier Carrasco 	int ret = 0;
558*3af35092SJavier Carrasco 
559*3af35092SJavier Carrasco 	mutex_lock(&data->dev_access_lock);
560*3af35092SJavier Carrasco 
561*3af35092SJavier Carrasco 	switch (type) {
562*3af35092SJavier Carrasco 	case hwmon_temp:
563*3af35092SJavier Carrasco 		ret = cc2_measurement(data, type, val);
564*3af35092SJavier Carrasco 		break;
565*3af35092SJavier Carrasco 	case hwmon_humidity:
566*3af35092SJavier Carrasco 		switch (attr) {
567*3af35092SJavier Carrasco 		case hwmon_humidity_input:
568*3af35092SJavier Carrasco 			ret = cc2_measurement(data, type, val);
569*3af35092SJavier Carrasco 			break;
570*3af35092SJavier Carrasco 		case hwmon_humidity_min:
571*3af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_L_ON, val);
572*3af35092SJavier Carrasco 			break;
573*3af35092SJavier Carrasco 		case hwmon_humidity_min_hyst:
574*3af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_L_OFF, val);
575*3af35092SJavier Carrasco 			break;
576*3af35092SJavier Carrasco 		case hwmon_humidity_max:
577*3af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_H_ON, val);
578*3af35092SJavier Carrasco 			break;
579*3af35092SJavier Carrasco 		case hwmon_humidity_max_hyst:
580*3af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_H_OFF, val);
581*3af35092SJavier Carrasco 			break;
582*3af35092SJavier Carrasco 		case hwmon_humidity_min_alarm:
583*3af35092SJavier Carrasco 			ret = cc2_humidity_min_alarm_status(data, val);
584*3af35092SJavier Carrasco 			break;
585*3af35092SJavier Carrasco 		case hwmon_humidity_max_alarm:
586*3af35092SJavier Carrasco 			ret = cc2_humidity_max_alarm_status(data, val);
587*3af35092SJavier Carrasco 			break;
588*3af35092SJavier Carrasco 		default:
589*3af35092SJavier Carrasco 			ret = -EOPNOTSUPP;
590*3af35092SJavier Carrasco 		}
591*3af35092SJavier Carrasco 		break;
592*3af35092SJavier Carrasco 	default:
593*3af35092SJavier Carrasco 		ret = -EOPNOTSUPP;
594*3af35092SJavier Carrasco 	}
595*3af35092SJavier Carrasco 
596*3af35092SJavier Carrasco 	mutex_unlock(&data->dev_access_lock);
597*3af35092SJavier Carrasco 
598*3af35092SJavier Carrasco 	return ret;
599*3af35092SJavier Carrasco }
600*3af35092SJavier Carrasco 
601*3af35092SJavier Carrasco static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
602*3af35092SJavier Carrasco 		     int channel, long val)
603*3af35092SJavier Carrasco {
604*3af35092SJavier Carrasco 	struct cc2_data *data = dev_get_drvdata(dev);
605*3af35092SJavier Carrasco 	int ret;
606*3af35092SJavier Carrasco 	u16 arg;
607*3af35092SJavier Carrasco 	u8 cmd;
608*3af35092SJavier Carrasco 
609*3af35092SJavier Carrasco 	if (type != hwmon_humidity)
610*3af35092SJavier Carrasco 		return -EOPNOTSUPP;
611*3af35092SJavier Carrasco 
612*3af35092SJavier Carrasco 	if (val < 0 || val > CC2_RH_MAX)
613*3af35092SJavier Carrasco 		return -EINVAL;
614*3af35092SJavier Carrasco 
615*3af35092SJavier Carrasco 	mutex_lock(&data->dev_access_lock);
616*3af35092SJavier Carrasco 
617*3af35092SJavier Carrasco 	switch (attr) {
618*3af35092SJavier Carrasco 	case hwmon_humidity_min:
619*3af35092SJavier Carrasco 		cmd = CC2_W_ALARM_L_ON;
620*3af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
621*3af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
622*3af35092SJavier Carrasco 		break;
623*3af35092SJavier Carrasco 
624*3af35092SJavier Carrasco 	case hwmon_humidity_min_hyst:
625*3af35092SJavier Carrasco 		cmd = CC2_W_ALARM_L_OFF;
626*3af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
627*3af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
628*3af35092SJavier Carrasco 		break;
629*3af35092SJavier Carrasco 
630*3af35092SJavier Carrasco 	case hwmon_humidity_max:
631*3af35092SJavier Carrasco 		cmd = CC2_W_ALARM_H_ON;
632*3af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
633*3af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
634*3af35092SJavier Carrasco 		break;
635*3af35092SJavier Carrasco 
636*3af35092SJavier Carrasco 	case hwmon_humidity_max_hyst:
637*3af35092SJavier Carrasco 		cmd = CC2_W_ALARM_H_OFF;
638*3af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
639*3af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
640*3af35092SJavier Carrasco 		break;
641*3af35092SJavier Carrasco 
642*3af35092SJavier Carrasco 	default:
643*3af35092SJavier Carrasco 		ret = -EOPNOTSUPP;
644*3af35092SJavier Carrasco 		break;
645*3af35092SJavier Carrasco 	}
646*3af35092SJavier Carrasco 
647*3af35092SJavier Carrasco 	mutex_unlock(&data->dev_access_lock);
648*3af35092SJavier Carrasco 
649*3af35092SJavier Carrasco 	return ret;
650*3af35092SJavier Carrasco }
651*3af35092SJavier Carrasco 
652*3af35092SJavier Carrasco static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
653*3af35092SJavier Carrasco {
654*3af35092SJavier Carrasco 	int ret = 0;
655*3af35092SJavier Carrasco 
656*3af35092SJavier Carrasco 	data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
657*3af35092SJavier Carrasco 	if (data->irq_ready > 0) {
658*3af35092SJavier Carrasco 		init_completion(&data->complete);
659*3af35092SJavier Carrasco 		ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
660*3af35092SJavier Carrasco 						cc2_ready_interrupt,
661*3af35092SJavier Carrasco 						IRQF_ONESHOT |
662*3af35092SJavier Carrasco 						IRQF_TRIGGER_RISING,
663*3af35092SJavier Carrasco 						dev_name(dev), data);
664*3af35092SJavier Carrasco 	}
665*3af35092SJavier Carrasco 
666*3af35092SJavier Carrasco 	return ret;
667*3af35092SJavier Carrasco }
668*3af35092SJavier Carrasco 
669*3af35092SJavier Carrasco static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
670*3af35092SJavier Carrasco {
671*3af35092SJavier Carrasco 	int ret;
672*3af35092SJavier Carrasco 
673*3af35092SJavier Carrasco 	data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
674*3af35092SJavier Carrasco 	if (data->irq_low > 0) {
675*3af35092SJavier Carrasco 		ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
676*3af35092SJavier Carrasco 						cc2_low_interrupt,
677*3af35092SJavier Carrasco 						IRQF_ONESHOT |
678*3af35092SJavier Carrasco 						IRQF_TRIGGER_RISING,
679*3af35092SJavier Carrasco 						dev_name(dev), data);
680*3af35092SJavier Carrasco 		if (!ret)
681*3af35092SJavier Carrasco 			data->rh_alarm.low_alarm_visible = true;
682*3af35092SJavier Carrasco 	}
683*3af35092SJavier Carrasco 
684*3af35092SJavier Carrasco 	data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
685*3af35092SJavier Carrasco 	if (data->irq_high > 0) {
686*3af35092SJavier Carrasco 		ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
687*3af35092SJavier Carrasco 						cc2_high_interrupt,
688*3af35092SJavier Carrasco 						IRQF_ONESHOT |
689*3af35092SJavier Carrasco 						IRQF_TRIGGER_RISING,
690*3af35092SJavier Carrasco 						dev_name(dev), data);
691*3af35092SJavier Carrasco 		if (!ret)
692*3af35092SJavier Carrasco 			data->rh_alarm.high_alarm_visible = true;
693*3af35092SJavier Carrasco 	}
694*3af35092SJavier Carrasco 
695*3af35092SJavier Carrasco 	return ret;
696*3af35092SJavier Carrasco }
697*3af35092SJavier Carrasco 
698*3af35092SJavier Carrasco static const struct hwmon_channel_info *cc2_info[] = {
699*3af35092SJavier Carrasco 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
700*3af35092SJavier Carrasco 	HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_MIN | HWMON_H_MAX |
701*3af35092SJavier Carrasco 			   HWMON_H_MIN_HYST | HWMON_H_MAX_HYST |
702*3af35092SJavier Carrasco 			   HWMON_H_MIN_ALARM | HWMON_H_MAX_ALARM),
703*3af35092SJavier Carrasco 	NULL
704*3af35092SJavier Carrasco };
705*3af35092SJavier Carrasco 
706*3af35092SJavier Carrasco static const struct hwmon_ops cc2_hwmon_ops = {
707*3af35092SJavier Carrasco 	.is_visible = cc2_is_visible,
708*3af35092SJavier Carrasco 	.read = cc2_read,
709*3af35092SJavier Carrasco 	.write = cc2_write,
710*3af35092SJavier Carrasco };
711*3af35092SJavier Carrasco 
712*3af35092SJavier Carrasco static const struct hwmon_chip_info cc2_chip_info = {
713*3af35092SJavier Carrasco 	.ops = &cc2_hwmon_ops,
714*3af35092SJavier Carrasco 	.info = cc2_info,
715*3af35092SJavier Carrasco };
716*3af35092SJavier Carrasco 
717*3af35092SJavier Carrasco static int cc2_probe(struct i2c_client *client)
718*3af35092SJavier Carrasco {
719*3af35092SJavier Carrasco 	struct cc2_data *data;
720*3af35092SJavier Carrasco 	struct device *dev = &client->dev;
721*3af35092SJavier Carrasco 	int ret;
722*3af35092SJavier Carrasco 
723*3af35092SJavier Carrasco 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
724*3af35092SJavier Carrasco 		return -EOPNOTSUPP;
725*3af35092SJavier Carrasco 
726*3af35092SJavier Carrasco 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
727*3af35092SJavier Carrasco 	if (!data)
728*3af35092SJavier Carrasco 		return -ENOMEM;
729*3af35092SJavier Carrasco 
730*3af35092SJavier Carrasco 	i2c_set_clientdata(client, data);
731*3af35092SJavier Carrasco 
732*3af35092SJavier Carrasco 	mutex_init(&data->dev_access_lock);
733*3af35092SJavier Carrasco 
734*3af35092SJavier Carrasco 	data->client = client;
735*3af35092SJavier Carrasco 
736*3af35092SJavier Carrasco 	data->regulator = devm_regulator_get_exclusive(dev, "vdd");
737*3af35092SJavier Carrasco 	if (IS_ERR(data->regulator)) {
738*3af35092SJavier Carrasco 		dev_err_probe(dev, PTR_ERR(data->regulator),
739*3af35092SJavier Carrasco 			      "Failed to get regulator\n");
740*3af35092SJavier Carrasco 		return PTR_ERR(data->regulator);
741*3af35092SJavier Carrasco 	}
742*3af35092SJavier Carrasco 
743*3af35092SJavier Carrasco 	ret = cc2_request_ready_irq(data, dev);
744*3af35092SJavier Carrasco 	if (ret) {
745*3af35092SJavier Carrasco 		dev_err_probe(dev, ret, "Failed to request ready irq\n");
746*3af35092SJavier Carrasco 		return ret;
747*3af35092SJavier Carrasco 	}
748*3af35092SJavier Carrasco 
749*3af35092SJavier Carrasco 	ret = cc2_request_alarm_irqs(data, dev);
750*3af35092SJavier Carrasco 	if (ret) {
751*3af35092SJavier Carrasco 		dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
752*3af35092SJavier Carrasco 		goto disable;
753*3af35092SJavier Carrasco 	}
754*3af35092SJavier Carrasco 
755*3af35092SJavier Carrasco 	data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
756*3af35092SJavier Carrasco 							   data, &cc2_chip_info,
757*3af35092SJavier Carrasco 							   NULL);
758*3af35092SJavier Carrasco 	if (IS_ERR(data->hwmon)) {
759*3af35092SJavier Carrasco 		dev_err_probe(dev, PTR_ERR(data->hwmon),
760*3af35092SJavier Carrasco 			      "Failed to register hwmon device\n");
761*3af35092SJavier Carrasco 		ret = PTR_ERR(data->hwmon);
762*3af35092SJavier Carrasco 	}
763*3af35092SJavier Carrasco 
764*3af35092SJavier Carrasco disable:
765*3af35092SJavier Carrasco 	cc2_disable(data);
766*3af35092SJavier Carrasco 
767*3af35092SJavier Carrasco 	return ret;
768*3af35092SJavier Carrasco }
769*3af35092SJavier Carrasco 
770*3af35092SJavier Carrasco static void cc2_remove(struct i2c_client *client)
771*3af35092SJavier Carrasco {
772*3af35092SJavier Carrasco 	struct cc2_data *data = i2c_get_clientdata(client);
773*3af35092SJavier Carrasco 
774*3af35092SJavier Carrasco 	cc2_disable(data);
775*3af35092SJavier Carrasco }
776*3af35092SJavier Carrasco 
777*3af35092SJavier Carrasco static const struct i2c_device_id cc2_id[] = {
778*3af35092SJavier Carrasco 	{ "cc2d23" },
779*3af35092SJavier Carrasco 	{ "cc2d23s" },
780*3af35092SJavier Carrasco 	{ "cc2d25" },
781*3af35092SJavier Carrasco 	{ "cc2d25s" },
782*3af35092SJavier Carrasco 	{ "cc2d33" },
783*3af35092SJavier Carrasco 	{ "cc2d33s" },
784*3af35092SJavier Carrasco 	{ "cc2d35" },
785*3af35092SJavier Carrasco 	{ "cc2d35s" },
786*3af35092SJavier Carrasco 	{ }
787*3af35092SJavier Carrasco };
788*3af35092SJavier Carrasco MODULE_DEVICE_TABLE(i2c, cc2_id);
789*3af35092SJavier Carrasco 
790*3af35092SJavier Carrasco static const struct of_device_id cc2_of_match[] = {
791*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d23" },
792*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d23s" },
793*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d25" },
794*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d25s" },
795*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d33" },
796*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d33s" },
797*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d35" },
798*3af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d35s" },
799*3af35092SJavier Carrasco 	{ },
800*3af35092SJavier Carrasco };
801*3af35092SJavier Carrasco MODULE_DEVICE_TABLE(of, cc2_of_match);
802*3af35092SJavier Carrasco 
803*3af35092SJavier Carrasco static struct i2c_driver cc2_driver = {
804*3af35092SJavier Carrasco 	.driver = {
805*3af35092SJavier Carrasco 		.name	= "cc2d23",
806*3af35092SJavier Carrasco 		.of_match_table = cc2_of_match,
807*3af35092SJavier Carrasco 	},
808*3af35092SJavier Carrasco 	.probe		= cc2_probe,
809*3af35092SJavier Carrasco 	.remove		= cc2_remove,
810*3af35092SJavier Carrasco 	.id_table = cc2_id,
811*3af35092SJavier Carrasco };
812*3af35092SJavier Carrasco module_i2c_driver(cc2_driver);
813*3af35092SJavier Carrasco 
814*3af35092SJavier Carrasco MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gamil.com>");
815*3af35092SJavier Carrasco MODULE_DESCRIPTION("Amphenol ChipCap 2 humidity and temperature sensor driver");
816*3af35092SJavier Carrasco MODULE_LICENSE("GPL");
817