xref: /linux/drivers/hwmon/chipcap2.c (revision f16fb6d23b68699eed97fe1edee0d8eecde14a67)
13af35092SJavier Carrasco // SPDX-License-Identifier: GPL-2.0+
23af35092SJavier Carrasco /*
33af35092SJavier Carrasco  * cc2.c - Support for the Amphenol ChipCap 2 relative humidity, temperature sensor
43af35092SJavier Carrasco  *
53af35092SJavier Carrasco  * Part numbers supported:
63af35092SJavier Carrasco  * CC2D23, CC2D23S, CC2D25, CC2D25S, CC2D33, CC2D33S, CC2D35, CC2D35S
73af35092SJavier Carrasco  *
83af35092SJavier Carrasco  * Author: Javier Carrasco <javier.carrasco.cruz@gmail.com>
93af35092SJavier Carrasco  *
103af35092SJavier Carrasco  * Datasheet and application notes:
113af35092SJavier Carrasco  * https://www.amphenol-sensors.com/en/telaire/humidity/527-humidity-sensors/3095-chipcap-2
123af35092SJavier Carrasco  */
133af35092SJavier Carrasco 
143af35092SJavier Carrasco #include <linux/bitfield.h>
153af35092SJavier Carrasco #include <linux/bits.h>
163af35092SJavier Carrasco #include <linux/completion.h>
173af35092SJavier Carrasco #include <linux/delay.h>
183af35092SJavier Carrasco #include <linux/hwmon.h>
193af35092SJavier Carrasco #include <linux/i2c.h>
203af35092SJavier Carrasco #include <linux/interrupt.h>
213af35092SJavier Carrasco #include <linux/irq.h>
223af35092SJavier Carrasco #include <linux/module.h>
233af35092SJavier Carrasco #include <linux/regulator/consumer.h>
243af35092SJavier Carrasco 
253af35092SJavier Carrasco #define CC2_START_CM			0xA0
263af35092SJavier Carrasco #define CC2_START_NOM			0x80
273af35092SJavier Carrasco #define CC2_R_ALARM_H_ON		0x18
283af35092SJavier Carrasco #define CC2_R_ALARM_H_OFF		0x19
293af35092SJavier Carrasco #define CC2_R_ALARM_L_ON		0x1A
303af35092SJavier Carrasco #define CC2_R_ALARM_L_OFF		0x1B
313af35092SJavier Carrasco #define CC2_RW_OFFSET			0x40
323af35092SJavier Carrasco #define CC2_W_ALARM_H_ON		(CC2_R_ALARM_H_ON + CC2_RW_OFFSET)
333af35092SJavier Carrasco #define CC2_W_ALARM_H_OFF		(CC2_R_ALARM_H_OFF + CC2_RW_OFFSET)
343af35092SJavier Carrasco #define CC2_W_ALARM_L_ON		(CC2_R_ALARM_L_ON + CC2_RW_OFFSET)
353af35092SJavier Carrasco #define CC2_W_ALARM_L_OFF		(CC2_R_ALARM_L_OFF + CC2_RW_OFFSET)
363af35092SJavier Carrasco 
373af35092SJavier Carrasco #define CC2_STATUS_FIELD		GENMASK(7, 6)
383af35092SJavier Carrasco #define CC2_STATUS_VALID_DATA		0x00
393af35092SJavier Carrasco #define CC2_STATUS_STALE_DATA		0x01
403af35092SJavier Carrasco #define CC2_STATUS_CMD_MODE		0x02
413af35092SJavier Carrasco 
423af35092SJavier Carrasco #define CC2_RESPONSE_FIELD		GENMASK(1, 0)
433af35092SJavier Carrasco #define CC2_RESPONSE_BUSY		0x00
443af35092SJavier Carrasco #define CC2_RESPONSE_ACK		0x01
453af35092SJavier Carrasco #define CC2_RESPONSE_NACK		0x02
463af35092SJavier Carrasco 
473af35092SJavier Carrasco #define CC2_ERR_CORR_EEPROM		BIT(2)
483af35092SJavier Carrasco #define CC2_ERR_UNCORR_EEPROM		BIT(3)
493af35092SJavier Carrasco #define CC2_ERR_RAM_PARITY		BIT(4)
503af35092SJavier Carrasco #define CC2_ERR_CONFIG_LOAD		BIT(5)
513af35092SJavier Carrasco 
523af35092SJavier Carrasco #define CC2_EEPROM_SIZE			10
533af35092SJavier Carrasco #define CC2_EEPROM_DATA_LEN		3
543af35092SJavier Carrasco #define CC2_MEASUREMENT_DATA_LEN	4
553af35092SJavier Carrasco 
563af35092SJavier Carrasco #define CC2_RH_DATA_FIELD		GENMASK(13, 0)
573af35092SJavier Carrasco 
583af35092SJavier Carrasco /* ensure clean off -> on transitions */
593af35092SJavier Carrasco #define CC2_POWER_CYCLE_MS		80
603af35092SJavier Carrasco 
613af35092SJavier Carrasco #define CC2_STARTUP_TO_DATA_MS		55
623af35092SJavier Carrasco #define CC2_RESP_START_CM_US		100
633af35092SJavier Carrasco #define CC2_RESP_EEPROM_R_US		100
643af35092SJavier Carrasco #define CC2_RESP_EEPROM_W_MS		12
653af35092SJavier Carrasco #define CC2_STARTUP_TIME_US		1250
663af35092SJavier Carrasco 
673af35092SJavier Carrasco #define CC2_RH_MAX			(100 * 1000U)
683af35092SJavier Carrasco 
693af35092SJavier Carrasco #define CC2_CM_RETRIES			5
703af35092SJavier Carrasco 
713af35092SJavier Carrasco struct cc2_rh_alarm_info {
723af35092SJavier Carrasco 	bool low_alarm;
733af35092SJavier Carrasco 	bool high_alarm;
743af35092SJavier Carrasco 	bool low_alarm_visible;
753af35092SJavier Carrasco 	bool high_alarm_visible;
763af35092SJavier Carrasco };
773af35092SJavier Carrasco 
783af35092SJavier Carrasco struct cc2_data {
793af35092SJavier Carrasco 	struct cc2_rh_alarm_info rh_alarm;
803af35092SJavier Carrasco 	struct completion complete;
813af35092SJavier Carrasco 	struct device *hwmon;
823af35092SJavier Carrasco 	struct i2c_client *client;
833af35092SJavier Carrasco 	struct mutex dev_access_lock; /* device access lock */
843af35092SJavier Carrasco 	struct regulator *regulator;
853af35092SJavier Carrasco 	const char *name;
863af35092SJavier Carrasco 	int irq_ready;
873af35092SJavier Carrasco 	int irq_low;
883af35092SJavier Carrasco 	int irq_high;
893af35092SJavier Carrasco 	bool process_irqs;
903af35092SJavier Carrasco };
913af35092SJavier Carrasco 
923af35092SJavier Carrasco enum cc2_chan_addr {
933af35092SJavier Carrasco 	CC2_CHAN_TEMP = 0,
943af35092SJavier Carrasco 	CC2_CHAN_HUMIDITY,
953af35092SJavier Carrasco };
963af35092SJavier Carrasco 
973af35092SJavier Carrasco /* %RH as a per cent mille from a register value */
983af35092SJavier Carrasco static long cc2_rh_convert(u16 data)
993af35092SJavier Carrasco {
1003af35092SJavier Carrasco 	unsigned long tmp = (data & CC2_RH_DATA_FIELD) * CC2_RH_MAX;
1013af35092SJavier Carrasco 
1023af35092SJavier Carrasco 	return tmp / ((1 << 14) - 1);
1033af35092SJavier Carrasco }
1043af35092SJavier Carrasco 
1053af35092SJavier Carrasco /* convert %RH to a register value */
1063af35092SJavier Carrasco static u16 cc2_rh_to_reg(long data)
1073af35092SJavier Carrasco {
1083af35092SJavier Carrasco 	return data * ((1 << 14) - 1) / CC2_RH_MAX;
1093af35092SJavier Carrasco }
1103af35092SJavier Carrasco 
1113af35092SJavier Carrasco /* temperature in milli degrees celsius from a register value */
1123af35092SJavier Carrasco static long cc2_temp_convert(u16 data)
1133af35092SJavier Carrasco {
1143af35092SJavier Carrasco 	unsigned long tmp = ((data >> 2) * 165 * 1000U) / ((1 << 14) - 1);
1153af35092SJavier Carrasco 
1163af35092SJavier Carrasco 	return tmp - 40 * 1000U;
1173af35092SJavier Carrasco }
1183af35092SJavier Carrasco 
1193af35092SJavier Carrasco static int cc2_enable(struct cc2_data *data)
1203af35092SJavier Carrasco {
1213af35092SJavier Carrasco 	int ret;
1223af35092SJavier Carrasco 
1233af35092SJavier Carrasco 	/* exclusive regulator, check in case a disable failed */
1243af35092SJavier Carrasco 	if (regulator_is_enabled(data->regulator))
1253af35092SJavier Carrasco 		return 0;
1263af35092SJavier Carrasco 
1273af35092SJavier Carrasco 	/* clear any pending completion */
1283af35092SJavier Carrasco 	try_wait_for_completion(&data->complete);
1293af35092SJavier Carrasco 
1303af35092SJavier Carrasco 	ret = regulator_enable(data->regulator);
1313af35092SJavier Carrasco 	if (ret < 0)
1323af35092SJavier Carrasco 		return ret;
1333af35092SJavier Carrasco 
1343af35092SJavier Carrasco 	usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
1353af35092SJavier Carrasco 
1363af35092SJavier Carrasco 	data->process_irqs = true;
1373af35092SJavier Carrasco 
1383af35092SJavier Carrasco 	return 0;
1393af35092SJavier Carrasco }
1403af35092SJavier Carrasco 
1413af35092SJavier Carrasco static void cc2_disable(struct cc2_data *data)
1423af35092SJavier Carrasco {
1433af35092SJavier Carrasco 	int err;
1443af35092SJavier Carrasco 
1453af35092SJavier Carrasco 	/* ignore alarms triggered by voltage toggling when powering up */
1463af35092SJavier Carrasco 	data->process_irqs = false;
1473af35092SJavier Carrasco 
1483af35092SJavier Carrasco 	/* exclusive regulator, check in case an enable failed */
1493af35092SJavier Carrasco 	if (regulator_is_enabled(data->regulator)) {
1503af35092SJavier Carrasco 		err = regulator_disable(data->regulator);
1513af35092SJavier Carrasco 		if (err)
1523af35092SJavier Carrasco 			dev_dbg(&data->client->dev, "Failed to disable device");
1533af35092SJavier Carrasco 	}
1543af35092SJavier Carrasco }
1553af35092SJavier Carrasco 
1563af35092SJavier Carrasco static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
1573af35092SJavier Carrasco {
1583af35092SJavier Carrasco 	int resp;
1593af35092SJavier Carrasco 
1603af35092SJavier Carrasco 	if (FIELD_GET(CC2_STATUS_FIELD, status) != CC2_STATUS_CMD_MODE) {
1613af35092SJavier Carrasco 		dev_dbg(dev, "Command sent out of command window\n");
1623af35092SJavier Carrasco 		return -ETIMEDOUT;
1633af35092SJavier Carrasco 	}
1643af35092SJavier Carrasco 
1653af35092SJavier Carrasco 	resp = FIELD_GET(CC2_RESPONSE_FIELD, status);
1663af35092SJavier Carrasco 	switch (resp) {
1673af35092SJavier Carrasco 	case CC2_RESPONSE_ACK:
1683af35092SJavier Carrasco 		return 0;
1693af35092SJavier Carrasco 	case CC2_RESPONSE_BUSY:
1703af35092SJavier Carrasco 		return -EBUSY;
1713af35092SJavier Carrasco 	case CC2_RESPONSE_NACK:
1723af35092SJavier Carrasco 		if (resp & CC2_ERR_CORR_EEPROM)
1733af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: corrected EEPROM\n");
1743af35092SJavier Carrasco 		if (resp & CC2_ERR_UNCORR_EEPROM)
1753af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: uncorrected EEPROM\n");
1763af35092SJavier Carrasco 		if (resp & CC2_ERR_RAM_PARITY)
1773af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: RAM parity\n");
1783af35092SJavier Carrasco 		if (resp & CC2_ERR_RAM_PARITY)
1793af35092SJavier Carrasco 			dev_dbg(dev, "Command failed: configuration error\n");
1803af35092SJavier Carrasco 		return -ENODATA;
1813af35092SJavier Carrasco 	default:
1823af35092SJavier Carrasco 		dev_dbg(dev, "Unknown command reply\n");
1833af35092SJavier Carrasco 		return -EINVAL;
1843af35092SJavier Carrasco 	}
1853af35092SJavier Carrasco }
1863af35092SJavier Carrasco 
1873af35092SJavier Carrasco static int cc2_read_command_status(struct i2c_client *client)
1883af35092SJavier Carrasco {
1893af35092SJavier Carrasco 	u8 status;
1903af35092SJavier Carrasco 	int ret;
1913af35092SJavier Carrasco 
1923af35092SJavier Carrasco 	ret = i2c_master_recv(client, &status, 1);
1933af35092SJavier Carrasco 	if (ret != 1) {
1943af35092SJavier Carrasco 		ret = ret < 0 ? ret : -EIO;
1953af35092SJavier Carrasco 		return ret;
1963af35092SJavier Carrasco 	}
1973af35092SJavier Carrasco 
1983af35092SJavier Carrasco 	return cc2_cmd_response_diagnostic(&client->dev, status);
1993af35092SJavier Carrasco }
2003af35092SJavier Carrasco 
2013af35092SJavier Carrasco /*
2023af35092SJavier Carrasco  * The command mode is only accessible after sending the START_CM command in the
2033af35092SJavier Carrasco  * first 10 ms after power-up. Only in case the command window is missed,
2043af35092SJavier Carrasco  * CC2_CM_RETRIES retries are attempted before giving up and returning an error.
2053af35092SJavier Carrasco  */
2063af35092SJavier Carrasco static int cc2_command_mode_start(struct cc2_data *data)
2073af35092SJavier Carrasco {
2083af35092SJavier Carrasco 	unsigned long timeout;
2093af35092SJavier Carrasco 	int i, ret;
2103af35092SJavier Carrasco 
2113af35092SJavier Carrasco 	for (i = 0; i < CC2_CM_RETRIES; i++) {
2123af35092SJavier Carrasco 		ret = cc2_enable(data);
2133af35092SJavier Carrasco 		if (ret < 0)
2143af35092SJavier Carrasco 			return ret;
2153af35092SJavier Carrasco 
2163af35092SJavier Carrasco 		ret = i2c_smbus_write_word_data(data->client, CC2_START_CM, 0);
2173af35092SJavier Carrasco 		if (ret < 0)
2183af35092SJavier Carrasco 			return ret;
2193af35092SJavier Carrasco 
2203af35092SJavier Carrasco 		if (data->irq_ready > 0) {
2213af35092SJavier Carrasco 			timeout = usecs_to_jiffies(2 * CC2_RESP_START_CM_US);
2223af35092SJavier Carrasco 			ret = wait_for_completion_timeout(&data->complete,
2233af35092SJavier Carrasco 							  timeout);
2243af35092SJavier Carrasco 			if (!ret)
2253af35092SJavier Carrasco 				return -ETIMEDOUT;
2263af35092SJavier Carrasco 		} else {
2273af35092SJavier Carrasco 			usleep_range(CC2_RESP_START_CM_US,
2283af35092SJavier Carrasco 				     2 * CC2_RESP_START_CM_US);
2293af35092SJavier Carrasco 		}
2303af35092SJavier Carrasco 		ret = cc2_read_command_status(data->client);
2313af35092SJavier Carrasco 		if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES)
2323af35092SJavier Carrasco 			break;
2333af35092SJavier Carrasco 
2343af35092SJavier Carrasco 		/* command window missed, prepare for a retry */
2353af35092SJavier Carrasco 		cc2_disable(data);
2363af35092SJavier Carrasco 		msleep(CC2_POWER_CYCLE_MS);
2373af35092SJavier Carrasco 	}
2383af35092SJavier Carrasco 
2393af35092SJavier Carrasco 	return ret;
2403af35092SJavier Carrasco }
2413af35092SJavier Carrasco 
2423af35092SJavier Carrasco /* Sending a Start_NOM command finishes the command mode immediately with no
2433af35092SJavier Carrasco  * reply and the device enters normal operation mode
2443af35092SJavier Carrasco  */
2453af35092SJavier Carrasco static int cc2_command_mode_finish(struct cc2_data *data)
2463af35092SJavier Carrasco {
2473af35092SJavier Carrasco 	int ret;
2483af35092SJavier Carrasco 
2493af35092SJavier Carrasco 	ret = i2c_smbus_write_word_data(data->client, CC2_START_NOM, 0);
2503af35092SJavier Carrasco 	if (ret < 0)
2513af35092SJavier Carrasco 		return ret;
2523af35092SJavier Carrasco 
2533af35092SJavier Carrasco 	return 0;
2543af35092SJavier Carrasco }
2553af35092SJavier Carrasco 
2563af35092SJavier Carrasco static int cc2_write_reg(struct cc2_data *data, u8 reg, u16 val)
2573af35092SJavier Carrasco {
2583af35092SJavier Carrasco 	unsigned long timeout;
2593af35092SJavier Carrasco 	int ret;
2603af35092SJavier Carrasco 
2613af35092SJavier Carrasco 	ret = cc2_command_mode_start(data);
2623af35092SJavier Carrasco 	if (ret < 0)
2633af35092SJavier Carrasco 		goto disable;
2643af35092SJavier Carrasco 
2653af35092SJavier Carrasco 	cpu_to_be16s(&val);
2663af35092SJavier Carrasco 	ret = i2c_smbus_write_word_data(data->client, reg, val);
2673af35092SJavier Carrasco 	if (ret < 0)
2683af35092SJavier Carrasco 		goto disable;
2693af35092SJavier Carrasco 
2703af35092SJavier Carrasco 	if (data->irq_ready > 0) {
2713af35092SJavier Carrasco 		timeout = msecs_to_jiffies(2 * CC2_RESP_EEPROM_W_MS);
2723af35092SJavier Carrasco 		ret = wait_for_completion_timeout(&data->complete, timeout);
2733af35092SJavier Carrasco 		if (!ret) {
2743af35092SJavier Carrasco 			ret = -ETIMEDOUT;
2753af35092SJavier Carrasco 			goto disable;
2763af35092SJavier Carrasco 		}
2773af35092SJavier Carrasco 	} else {
2783af35092SJavier Carrasco 		msleep(CC2_RESP_EEPROM_W_MS);
2793af35092SJavier Carrasco 	}
2803af35092SJavier Carrasco 
2813af35092SJavier Carrasco 	ret = cc2_read_command_status(data->client);
2823af35092SJavier Carrasco 
2833af35092SJavier Carrasco disable:
2843af35092SJavier Carrasco 	cc2_disable(data);
2853af35092SJavier Carrasco 
2863af35092SJavier Carrasco 	return ret;
2873af35092SJavier Carrasco }
2883af35092SJavier Carrasco 
2893af35092SJavier Carrasco static int cc2_read_reg(struct cc2_data *data, u8 reg, u16 *val)
2903af35092SJavier Carrasco {
2913af35092SJavier Carrasco 	u8 buf[CC2_EEPROM_DATA_LEN];
2923af35092SJavier Carrasco 	unsigned long timeout;
2933af35092SJavier Carrasco 	int ret;
2943af35092SJavier Carrasco 
2953af35092SJavier Carrasco 	ret = cc2_command_mode_start(data);
2963af35092SJavier Carrasco 	if (ret < 0)
2973af35092SJavier Carrasco 		return ret;
2983af35092SJavier Carrasco 
2993af35092SJavier Carrasco 	ret = i2c_smbus_write_word_data(data->client, reg, 0);
3003af35092SJavier Carrasco 	if (ret < 0)
3013af35092SJavier Carrasco 		return ret;
3023af35092SJavier Carrasco 
3033af35092SJavier Carrasco 	if (data->irq_ready > 0) {
3043af35092SJavier Carrasco 		timeout = usecs_to_jiffies(2 * CC2_RESP_EEPROM_R_US);
3053af35092SJavier Carrasco 		ret = wait_for_completion_timeout(&data->complete, timeout);
3063af35092SJavier Carrasco 		if (!ret)
3073af35092SJavier Carrasco 			return -ETIMEDOUT;
3083af35092SJavier Carrasco 
3093af35092SJavier Carrasco 	} else {
3103af35092SJavier Carrasco 		usleep_range(CC2_RESP_EEPROM_R_US, CC2_RESP_EEPROM_R_US + 10);
3113af35092SJavier Carrasco 	}
3123af35092SJavier Carrasco 	ret = i2c_master_recv(data->client, buf, CC2_EEPROM_DATA_LEN);
3133af35092SJavier Carrasco 	if (ret != CC2_EEPROM_DATA_LEN)
3143af35092SJavier Carrasco 		return ret < 0 ? ret : -EIO;
3153af35092SJavier Carrasco 
3163af35092SJavier Carrasco 	*val = be16_to_cpup((__be16 *)&buf[1]);
3173af35092SJavier Carrasco 
3183af35092SJavier Carrasco 	return cc2_read_command_status(data->client);
3193af35092SJavier Carrasco }
3203af35092SJavier Carrasco 
3213af35092SJavier Carrasco static int cc2_get_reg_val(struct cc2_data *data, u8 reg, long *val)
3223af35092SJavier Carrasco {
3233af35092SJavier Carrasco 	u16 reg_val;
3243af35092SJavier Carrasco 	int ret;
3253af35092SJavier Carrasco 
3263af35092SJavier Carrasco 	ret = cc2_read_reg(data, reg, &reg_val);
327*f16fb6d2SJavier Carrasco 	if (!ret)
3283af35092SJavier Carrasco 		*val = cc2_rh_convert(reg_val);
329*f16fb6d2SJavier Carrasco 
3303af35092SJavier Carrasco 	cc2_disable(data);
3313af35092SJavier Carrasco 
3323af35092SJavier Carrasco 	return ret;
3333af35092SJavier Carrasco }
3343af35092SJavier Carrasco 
3353af35092SJavier Carrasco static int cc2_data_fetch(struct i2c_client *client,
3363af35092SJavier Carrasco 			  enum hwmon_sensor_types type, long *val)
3373af35092SJavier Carrasco {
3383af35092SJavier Carrasco 	u8 data[CC2_MEASUREMENT_DATA_LEN];
3393af35092SJavier Carrasco 	u8 status;
3403af35092SJavier Carrasco 	int ret;
3413af35092SJavier Carrasco 
3423af35092SJavier Carrasco 	ret = i2c_master_recv(client, data, CC2_MEASUREMENT_DATA_LEN);
3433af35092SJavier Carrasco 	if (ret != CC2_MEASUREMENT_DATA_LEN) {
3443af35092SJavier Carrasco 		ret = ret < 0 ? ret : -EIO;
3453af35092SJavier Carrasco 		return ret;
3463af35092SJavier Carrasco 	}
3473af35092SJavier Carrasco 	status = FIELD_GET(CC2_STATUS_FIELD, data[0]);
3483af35092SJavier Carrasco 	if (status == CC2_STATUS_STALE_DATA)
3493af35092SJavier Carrasco 		return -EBUSY;
3503af35092SJavier Carrasco 
3513af35092SJavier Carrasco 	if (status != CC2_STATUS_VALID_DATA)
3523af35092SJavier Carrasco 		return -EIO;
3533af35092SJavier Carrasco 
3543af35092SJavier Carrasco 	switch (type) {
3553af35092SJavier Carrasco 	case hwmon_humidity:
3563af35092SJavier Carrasco 		*val = cc2_rh_convert(be16_to_cpup((__be16 *)&data[0]));
3573af35092SJavier Carrasco 		break;
3583af35092SJavier Carrasco 	case hwmon_temp:
3593af35092SJavier Carrasco 		*val = cc2_temp_convert(be16_to_cpup((__be16 *)&data[2]));
3603af35092SJavier Carrasco 		break;
3613af35092SJavier Carrasco 	default:
3623af35092SJavier Carrasco 		return -EINVAL;
3633af35092SJavier Carrasco 	}
3643af35092SJavier Carrasco 
3653af35092SJavier Carrasco 	return 0;
3663af35092SJavier Carrasco }
3673af35092SJavier Carrasco 
3683af35092SJavier Carrasco static int cc2_read_measurement(struct cc2_data *data,
3693af35092SJavier Carrasco 				enum hwmon_sensor_types type, long *val)
3703af35092SJavier Carrasco {
3713af35092SJavier Carrasco 	unsigned long timeout;
3723af35092SJavier Carrasco 	int ret;
3733af35092SJavier Carrasco 
3743af35092SJavier Carrasco 	if (data->irq_ready > 0) {
3753af35092SJavier Carrasco 		timeout = msecs_to_jiffies(CC2_STARTUP_TO_DATA_MS * 2);
3763af35092SJavier Carrasco 		ret = wait_for_completion_timeout(&data->complete, timeout);
3773af35092SJavier Carrasco 		if (!ret)
3783af35092SJavier Carrasco 			return -ETIMEDOUT;
3793af35092SJavier Carrasco 
3803af35092SJavier Carrasco 	} else {
3813af35092SJavier Carrasco 		msleep(CC2_STARTUP_TO_DATA_MS);
3823af35092SJavier Carrasco 	}
3833af35092SJavier Carrasco 
3843af35092SJavier Carrasco 	ret = cc2_data_fetch(data->client, type, val);
3853af35092SJavier Carrasco 
3863af35092SJavier Carrasco 	return ret;
3873af35092SJavier Carrasco }
3883af35092SJavier Carrasco 
3893af35092SJavier Carrasco /*
3903af35092SJavier Carrasco  * A measurement requires enabling the device, waiting for the automatic
3913af35092SJavier Carrasco  * measurement to finish, reading the measurement data and disabling the device
3923af35092SJavier Carrasco  * again.
3933af35092SJavier Carrasco  */
3943af35092SJavier Carrasco static int cc2_measurement(struct cc2_data *data, enum hwmon_sensor_types type,
3953af35092SJavier Carrasco 			   long *val)
3963af35092SJavier Carrasco {
3973af35092SJavier Carrasco 	int ret;
3983af35092SJavier Carrasco 
3993af35092SJavier Carrasco 	ret = cc2_enable(data);
4003af35092SJavier Carrasco 	if (ret)
4013af35092SJavier Carrasco 		return ret;
4023af35092SJavier Carrasco 
4033af35092SJavier Carrasco 	ret = cc2_read_measurement(data, type, val);
4043af35092SJavier Carrasco 
4053af35092SJavier Carrasco 	cc2_disable(data);
4063af35092SJavier Carrasco 
4073af35092SJavier Carrasco 	return ret;
4083af35092SJavier Carrasco }
4093af35092SJavier Carrasco 
4103af35092SJavier Carrasco /*
4113af35092SJavier Carrasco  * In order to check alarm status, the corresponding ALARM_OFF (hysteresis)
4123af35092SJavier Carrasco  * register must be read and a new measurement must be carried out to trigger
4133af35092SJavier Carrasco  * the alarm signals. Given that the device carries out a measurement after
4143af35092SJavier Carrasco  * exiting the command mode, there is no need to force two power-up sequences.
4153af35092SJavier Carrasco  * Instead, a NOM command is sent and the device is disabled after the
4163af35092SJavier Carrasco  * measurement is read.
4173af35092SJavier Carrasco  */
4183af35092SJavier Carrasco static int cc2_read_hyst_and_measure(struct cc2_data *data, u8 reg,
4193af35092SJavier Carrasco 				     long *hyst, long *measurement)
4203af35092SJavier Carrasco {
4213af35092SJavier Carrasco 	u16 reg_val;
4223af35092SJavier Carrasco 	int ret;
4233af35092SJavier Carrasco 
4243af35092SJavier Carrasco 	ret = cc2_read_reg(data, reg, &reg_val);
4253af35092SJavier Carrasco 	if (ret)
4263af35092SJavier Carrasco 		goto disable;
4273af35092SJavier Carrasco 
4283af35092SJavier Carrasco 	*hyst = cc2_rh_convert(reg_val);
4293af35092SJavier Carrasco 
4303af35092SJavier Carrasco 	ret = cc2_command_mode_finish(data);
4313af35092SJavier Carrasco 	if (ret)
4323af35092SJavier Carrasco 		goto disable;
4333af35092SJavier Carrasco 
4343af35092SJavier Carrasco 	ret = cc2_read_measurement(data, hwmon_humidity, measurement);
4353af35092SJavier Carrasco 
4363af35092SJavier Carrasco disable:
4373af35092SJavier Carrasco 	cc2_disable(data);
4383af35092SJavier Carrasco 
4393af35092SJavier Carrasco 	return ret;
4403af35092SJavier Carrasco }
4413af35092SJavier Carrasco 
4423af35092SJavier Carrasco static umode_t cc2_is_visible(const void *data, enum hwmon_sensor_types type,
4433af35092SJavier Carrasco 			      u32 attr, int channel)
4443af35092SJavier Carrasco {
4453af35092SJavier Carrasco 	const struct cc2_data *cc2 = data;
4463af35092SJavier Carrasco 
4473af35092SJavier Carrasco 	switch (type) {
4483af35092SJavier Carrasco 	case hwmon_humidity:
4493af35092SJavier Carrasco 		switch (attr) {
4503af35092SJavier Carrasco 		case hwmon_humidity_input:
4513af35092SJavier Carrasco 			return 0444;
4523af35092SJavier Carrasco 		case hwmon_humidity_min_alarm:
4533af35092SJavier Carrasco 			return cc2->rh_alarm.low_alarm_visible ? 0444 : 0;
4543af35092SJavier Carrasco 		case hwmon_humidity_max_alarm:
4553af35092SJavier Carrasco 			return cc2->rh_alarm.high_alarm_visible ? 0444 : 0;
4563af35092SJavier Carrasco 		case hwmon_humidity_min:
4573af35092SJavier Carrasco 		case hwmon_humidity_min_hyst:
4583af35092SJavier Carrasco 			return cc2->rh_alarm.low_alarm_visible ? 0644 : 0;
4593af35092SJavier Carrasco 		case hwmon_humidity_max:
4603af35092SJavier Carrasco 		case hwmon_humidity_max_hyst:
4613af35092SJavier Carrasco 			return cc2->rh_alarm.high_alarm_visible ? 0644 : 0;
4623af35092SJavier Carrasco 		default:
4633af35092SJavier Carrasco 			return 0;
4643af35092SJavier Carrasco 		}
4653af35092SJavier Carrasco 	case hwmon_temp:
4663af35092SJavier Carrasco 		switch (attr) {
4673af35092SJavier Carrasco 		case hwmon_temp_input:
4683af35092SJavier Carrasco 			return 0444;
4693af35092SJavier Carrasco 		default:
4703af35092SJavier Carrasco 			return 0;
4713af35092SJavier Carrasco 		}
4723af35092SJavier Carrasco 	default:
4733af35092SJavier Carrasco 		break;
4743af35092SJavier Carrasco 	}
4753af35092SJavier Carrasco 
4763af35092SJavier Carrasco 	return 0;
4773af35092SJavier Carrasco }
4783af35092SJavier Carrasco 
4793af35092SJavier Carrasco static irqreturn_t cc2_ready_interrupt(int irq, void *data)
4803af35092SJavier Carrasco {
4813af35092SJavier Carrasco 	struct cc2_data *cc2 = data;
4823af35092SJavier Carrasco 
4833af35092SJavier Carrasco 	if (cc2->process_irqs)
4843af35092SJavier Carrasco 		complete(&cc2->complete);
4853af35092SJavier Carrasco 
4863af35092SJavier Carrasco 	return IRQ_HANDLED;
4873af35092SJavier Carrasco }
4883af35092SJavier Carrasco 
4893af35092SJavier Carrasco static irqreturn_t cc2_low_interrupt(int irq, void *data)
4903af35092SJavier Carrasco {
4913af35092SJavier Carrasco 	struct cc2_data *cc2 = data;
4923af35092SJavier Carrasco 
4933af35092SJavier Carrasco 	if (cc2->process_irqs) {
4943af35092SJavier Carrasco 		hwmon_notify_event(cc2->hwmon, hwmon_humidity,
4953af35092SJavier Carrasco 				   hwmon_humidity_min_alarm, CC2_CHAN_HUMIDITY);
4963af35092SJavier Carrasco 		cc2->rh_alarm.low_alarm = true;
4973af35092SJavier Carrasco 	}
4983af35092SJavier Carrasco 
4993af35092SJavier Carrasco 	return IRQ_HANDLED;
5003af35092SJavier Carrasco }
5013af35092SJavier Carrasco 
5023af35092SJavier Carrasco static irqreturn_t cc2_high_interrupt(int irq, void *data)
5033af35092SJavier Carrasco {
5043af35092SJavier Carrasco 	struct cc2_data *cc2 = data;
5053af35092SJavier Carrasco 
5063af35092SJavier Carrasco 	if (cc2->process_irqs) {
5073af35092SJavier Carrasco 		hwmon_notify_event(cc2->hwmon, hwmon_humidity,
5083af35092SJavier Carrasco 				   hwmon_humidity_max_alarm, CC2_CHAN_HUMIDITY);
5093af35092SJavier Carrasco 		cc2->rh_alarm.high_alarm = true;
5103af35092SJavier Carrasco 	}
5113af35092SJavier Carrasco 
5123af35092SJavier Carrasco 	return IRQ_HANDLED;
5133af35092SJavier Carrasco }
5143af35092SJavier Carrasco 
5153af35092SJavier Carrasco static int cc2_humidity_min_alarm_status(struct cc2_data *data, long *val)
5163af35092SJavier Carrasco {
5173af35092SJavier Carrasco 	long measurement, min_hyst;
5183af35092SJavier Carrasco 	int ret;
5193af35092SJavier Carrasco 
5203af35092SJavier Carrasco 	ret = cc2_read_hyst_and_measure(data, CC2_R_ALARM_L_OFF, &min_hyst,
5213af35092SJavier Carrasco 					&measurement);
5223af35092SJavier Carrasco 	if (ret < 0)
5233af35092SJavier Carrasco 		return ret;
5243af35092SJavier Carrasco 
5253af35092SJavier Carrasco 	if (data->rh_alarm.low_alarm) {
5263af35092SJavier Carrasco 		*val = (measurement < min_hyst) ? 1 : 0;
5273af35092SJavier Carrasco 		data->rh_alarm.low_alarm = *val;
5283af35092SJavier Carrasco 	} else {
5293af35092SJavier Carrasco 		*val = 0;
5303af35092SJavier Carrasco 	}
5313af35092SJavier Carrasco 
5323af35092SJavier Carrasco 	return 0;
5333af35092SJavier Carrasco }
5343af35092SJavier Carrasco 
5353af35092SJavier Carrasco static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val)
5363af35092SJavier Carrasco {
5373af35092SJavier Carrasco 	long measurement, max_hyst;
5383af35092SJavier Carrasco 	int ret;
5393af35092SJavier Carrasco 
5403af35092SJavier Carrasco 	ret = cc2_read_hyst_and_measure(data, CC2_R_ALARM_H_OFF, &max_hyst,
5413af35092SJavier Carrasco 					&measurement);
5423af35092SJavier Carrasco 	if (ret < 0)
5433af35092SJavier Carrasco 		return ret;
5443af35092SJavier Carrasco 
5453af35092SJavier Carrasco 	if (data->rh_alarm.high_alarm) {
5463af35092SJavier Carrasco 		*val = (measurement > max_hyst) ? 1 : 0;
5473af35092SJavier Carrasco 		data->rh_alarm.high_alarm = *val;
5483af35092SJavier Carrasco 	} else {
5493af35092SJavier Carrasco 		*val = 0;
5503af35092SJavier Carrasco 	}
5513af35092SJavier Carrasco 
5523af35092SJavier Carrasco 	return 0;
5533af35092SJavier Carrasco }
5543af35092SJavier Carrasco 
5553af35092SJavier Carrasco static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
5563af35092SJavier Carrasco 		    int channel, long *val)
5573af35092SJavier Carrasco {
5583af35092SJavier Carrasco 	struct cc2_data *data = dev_get_drvdata(dev);
5593af35092SJavier Carrasco 	int ret = 0;
5603af35092SJavier Carrasco 
5613af35092SJavier Carrasco 	mutex_lock(&data->dev_access_lock);
5623af35092SJavier Carrasco 
5633af35092SJavier Carrasco 	switch (type) {
5643af35092SJavier Carrasco 	case hwmon_temp:
5653af35092SJavier Carrasco 		ret = cc2_measurement(data, type, val);
5663af35092SJavier Carrasco 		break;
5673af35092SJavier Carrasco 	case hwmon_humidity:
5683af35092SJavier Carrasco 		switch (attr) {
5693af35092SJavier Carrasco 		case hwmon_humidity_input:
5703af35092SJavier Carrasco 			ret = cc2_measurement(data, type, val);
5713af35092SJavier Carrasco 			break;
5723af35092SJavier Carrasco 		case hwmon_humidity_min:
5733af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_L_ON, val);
5743af35092SJavier Carrasco 			break;
5753af35092SJavier Carrasco 		case hwmon_humidity_min_hyst:
5763af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_L_OFF, val);
5773af35092SJavier Carrasco 			break;
5783af35092SJavier Carrasco 		case hwmon_humidity_max:
5793af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_H_ON, val);
5803af35092SJavier Carrasco 			break;
5813af35092SJavier Carrasco 		case hwmon_humidity_max_hyst:
5823af35092SJavier Carrasco 			ret = cc2_get_reg_val(data, CC2_R_ALARM_H_OFF, val);
5833af35092SJavier Carrasco 			break;
5843af35092SJavier Carrasco 		case hwmon_humidity_min_alarm:
5853af35092SJavier Carrasco 			ret = cc2_humidity_min_alarm_status(data, val);
5863af35092SJavier Carrasco 			break;
5873af35092SJavier Carrasco 		case hwmon_humidity_max_alarm:
5883af35092SJavier Carrasco 			ret = cc2_humidity_max_alarm_status(data, val);
5893af35092SJavier Carrasco 			break;
5903af35092SJavier Carrasco 		default:
5913af35092SJavier Carrasco 			ret = -EOPNOTSUPP;
5923af35092SJavier Carrasco 		}
5933af35092SJavier Carrasco 		break;
5943af35092SJavier Carrasco 	default:
5953af35092SJavier Carrasco 		ret = -EOPNOTSUPP;
5963af35092SJavier Carrasco 	}
5973af35092SJavier Carrasco 
5983af35092SJavier Carrasco 	mutex_unlock(&data->dev_access_lock);
5993af35092SJavier Carrasco 
6003af35092SJavier Carrasco 	return ret;
6013af35092SJavier Carrasco }
6023af35092SJavier Carrasco 
6033af35092SJavier Carrasco static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
6043af35092SJavier Carrasco 		     int channel, long val)
6053af35092SJavier Carrasco {
6063af35092SJavier Carrasco 	struct cc2_data *data = dev_get_drvdata(dev);
6073af35092SJavier Carrasco 	int ret;
6083af35092SJavier Carrasco 	u16 arg;
6093af35092SJavier Carrasco 	u8 cmd;
6103af35092SJavier Carrasco 
6113af35092SJavier Carrasco 	if (type != hwmon_humidity)
6123af35092SJavier Carrasco 		return -EOPNOTSUPP;
6133af35092SJavier Carrasco 
6143af35092SJavier Carrasco 	if (val < 0 || val > CC2_RH_MAX)
6153af35092SJavier Carrasco 		return -EINVAL;
6163af35092SJavier Carrasco 
6173af35092SJavier Carrasco 	mutex_lock(&data->dev_access_lock);
6183af35092SJavier Carrasco 
6193af35092SJavier Carrasco 	switch (attr) {
6203af35092SJavier Carrasco 	case hwmon_humidity_min:
6213af35092SJavier Carrasco 		cmd = CC2_W_ALARM_L_ON;
6223af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
6233af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
6243af35092SJavier Carrasco 		break;
6253af35092SJavier Carrasco 
6263af35092SJavier Carrasco 	case hwmon_humidity_min_hyst:
6273af35092SJavier Carrasco 		cmd = CC2_W_ALARM_L_OFF;
6283af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
6293af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
6303af35092SJavier Carrasco 		break;
6313af35092SJavier Carrasco 
6323af35092SJavier Carrasco 	case hwmon_humidity_max:
6333af35092SJavier Carrasco 		cmd = CC2_W_ALARM_H_ON;
6343af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
6353af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
6363af35092SJavier Carrasco 		break;
6373af35092SJavier Carrasco 
6383af35092SJavier Carrasco 	case hwmon_humidity_max_hyst:
6393af35092SJavier Carrasco 		cmd = CC2_W_ALARM_H_OFF;
6403af35092SJavier Carrasco 		arg = cc2_rh_to_reg(val);
6413af35092SJavier Carrasco 		ret = cc2_write_reg(data, cmd, arg);
6423af35092SJavier Carrasco 		break;
6433af35092SJavier Carrasco 
6443af35092SJavier Carrasco 	default:
6453af35092SJavier Carrasco 		ret = -EOPNOTSUPP;
6463af35092SJavier Carrasco 		break;
6473af35092SJavier Carrasco 	}
6483af35092SJavier Carrasco 
6493af35092SJavier Carrasco 	mutex_unlock(&data->dev_access_lock);
6503af35092SJavier Carrasco 
6513af35092SJavier Carrasco 	return ret;
6523af35092SJavier Carrasco }
6533af35092SJavier Carrasco 
6543af35092SJavier Carrasco static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
6553af35092SJavier Carrasco {
6563af35092SJavier Carrasco 	int ret = 0;
6573af35092SJavier Carrasco 
6583af35092SJavier Carrasco 	data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
6593af35092SJavier Carrasco 	if (data->irq_ready > 0) {
6603af35092SJavier Carrasco 		init_completion(&data->complete);
6613af35092SJavier Carrasco 		ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
6623af35092SJavier Carrasco 						cc2_ready_interrupt,
6633af35092SJavier Carrasco 						IRQF_ONESHOT |
6643af35092SJavier Carrasco 						IRQF_TRIGGER_RISING,
6653af35092SJavier Carrasco 						dev_name(dev), data);
6663af35092SJavier Carrasco 	}
6673af35092SJavier Carrasco 
6683af35092SJavier Carrasco 	return ret;
6693af35092SJavier Carrasco }
6703af35092SJavier Carrasco 
6713af35092SJavier Carrasco static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
6723af35092SJavier Carrasco {
6733af35092SJavier Carrasco 	int ret;
6743af35092SJavier Carrasco 
6753af35092SJavier Carrasco 	data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
6763af35092SJavier Carrasco 	if (data->irq_low > 0) {
6773af35092SJavier Carrasco 		ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
6783af35092SJavier Carrasco 						cc2_low_interrupt,
6793af35092SJavier Carrasco 						IRQF_ONESHOT |
6803af35092SJavier Carrasco 						IRQF_TRIGGER_RISING,
6813af35092SJavier Carrasco 						dev_name(dev), data);
6823af35092SJavier Carrasco 		if (!ret)
6833af35092SJavier Carrasco 			data->rh_alarm.low_alarm_visible = true;
6843af35092SJavier Carrasco 	}
6853af35092SJavier Carrasco 
6863af35092SJavier Carrasco 	data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
6873af35092SJavier Carrasco 	if (data->irq_high > 0) {
6883af35092SJavier Carrasco 		ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
6893af35092SJavier Carrasco 						cc2_high_interrupt,
6903af35092SJavier Carrasco 						IRQF_ONESHOT |
6913af35092SJavier Carrasco 						IRQF_TRIGGER_RISING,
6923af35092SJavier Carrasco 						dev_name(dev), data);
6933af35092SJavier Carrasco 		if (!ret)
6943af35092SJavier Carrasco 			data->rh_alarm.high_alarm_visible = true;
6953af35092SJavier Carrasco 	}
6963af35092SJavier Carrasco 
6973af35092SJavier Carrasco 	return ret;
6983af35092SJavier Carrasco }
6993af35092SJavier Carrasco 
7003af35092SJavier Carrasco static const struct hwmon_channel_info *cc2_info[] = {
7013af35092SJavier Carrasco 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
7023af35092SJavier Carrasco 	HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_MIN | HWMON_H_MAX |
7033af35092SJavier Carrasco 			   HWMON_H_MIN_HYST | HWMON_H_MAX_HYST |
7043af35092SJavier Carrasco 			   HWMON_H_MIN_ALARM | HWMON_H_MAX_ALARM),
7053af35092SJavier Carrasco 	NULL
7063af35092SJavier Carrasco };
7073af35092SJavier Carrasco 
7083af35092SJavier Carrasco static const struct hwmon_ops cc2_hwmon_ops = {
7093af35092SJavier Carrasco 	.is_visible = cc2_is_visible,
7103af35092SJavier Carrasco 	.read = cc2_read,
7113af35092SJavier Carrasco 	.write = cc2_write,
7123af35092SJavier Carrasco };
7133af35092SJavier Carrasco 
7143af35092SJavier Carrasco static const struct hwmon_chip_info cc2_chip_info = {
7153af35092SJavier Carrasco 	.ops = &cc2_hwmon_ops,
7163af35092SJavier Carrasco 	.info = cc2_info,
7173af35092SJavier Carrasco };
7183af35092SJavier Carrasco 
7193af35092SJavier Carrasco static int cc2_probe(struct i2c_client *client)
7203af35092SJavier Carrasco {
7213af35092SJavier Carrasco 	struct cc2_data *data;
7223af35092SJavier Carrasco 	struct device *dev = &client->dev;
7233af35092SJavier Carrasco 	int ret;
7243af35092SJavier Carrasco 
7253af35092SJavier Carrasco 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
7263af35092SJavier Carrasco 		return -EOPNOTSUPP;
7273af35092SJavier Carrasco 
7283af35092SJavier Carrasco 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
7293af35092SJavier Carrasco 	if (!data)
7303af35092SJavier Carrasco 		return -ENOMEM;
7313af35092SJavier Carrasco 
7323af35092SJavier Carrasco 	i2c_set_clientdata(client, data);
7333af35092SJavier Carrasco 
7343af35092SJavier Carrasco 	mutex_init(&data->dev_access_lock);
7353af35092SJavier Carrasco 
7363af35092SJavier Carrasco 	data->client = client;
7373af35092SJavier Carrasco 
7383af35092SJavier Carrasco 	data->regulator = devm_regulator_get_exclusive(dev, "vdd");
7393af35092SJavier Carrasco 	if (IS_ERR(data->regulator)) {
7403af35092SJavier Carrasco 		dev_err_probe(dev, PTR_ERR(data->regulator),
7413af35092SJavier Carrasco 			      "Failed to get regulator\n");
7423af35092SJavier Carrasco 		return PTR_ERR(data->regulator);
7433af35092SJavier Carrasco 	}
7443af35092SJavier Carrasco 
7453af35092SJavier Carrasco 	ret = cc2_request_ready_irq(data, dev);
7463af35092SJavier Carrasco 	if (ret) {
7473af35092SJavier Carrasco 		dev_err_probe(dev, ret, "Failed to request ready irq\n");
7483af35092SJavier Carrasco 		return ret;
7493af35092SJavier Carrasco 	}
7503af35092SJavier Carrasco 
7513af35092SJavier Carrasco 	ret = cc2_request_alarm_irqs(data, dev);
7523af35092SJavier Carrasco 	if (ret) {
7533af35092SJavier Carrasco 		dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
7543af35092SJavier Carrasco 		goto disable;
7553af35092SJavier Carrasco 	}
7563af35092SJavier Carrasco 
7573af35092SJavier Carrasco 	data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
7583af35092SJavier Carrasco 							   data, &cc2_chip_info,
7593af35092SJavier Carrasco 							   NULL);
7603af35092SJavier Carrasco 	if (IS_ERR(data->hwmon)) {
7613af35092SJavier Carrasco 		dev_err_probe(dev, PTR_ERR(data->hwmon),
7623af35092SJavier Carrasco 			      "Failed to register hwmon device\n");
7633af35092SJavier Carrasco 		ret = PTR_ERR(data->hwmon);
7643af35092SJavier Carrasco 	}
7653af35092SJavier Carrasco 
7663af35092SJavier Carrasco disable:
7673af35092SJavier Carrasco 	cc2_disable(data);
7683af35092SJavier Carrasco 
7693af35092SJavier Carrasco 	return ret;
7703af35092SJavier Carrasco }
7713af35092SJavier Carrasco 
7723af35092SJavier Carrasco static void cc2_remove(struct i2c_client *client)
7733af35092SJavier Carrasco {
7743af35092SJavier Carrasco 	struct cc2_data *data = i2c_get_clientdata(client);
7753af35092SJavier Carrasco 
7763af35092SJavier Carrasco 	cc2_disable(data);
7773af35092SJavier Carrasco }
7783af35092SJavier Carrasco 
7793af35092SJavier Carrasco static const struct i2c_device_id cc2_id[] = {
7803af35092SJavier Carrasco 	{ "cc2d23" },
7813af35092SJavier Carrasco 	{ "cc2d23s" },
7823af35092SJavier Carrasco 	{ "cc2d25" },
7833af35092SJavier Carrasco 	{ "cc2d25s" },
7843af35092SJavier Carrasco 	{ "cc2d33" },
7853af35092SJavier Carrasco 	{ "cc2d33s" },
7863af35092SJavier Carrasco 	{ "cc2d35" },
7873af35092SJavier Carrasco 	{ "cc2d35s" },
7883af35092SJavier Carrasco 	{ }
7893af35092SJavier Carrasco };
7903af35092SJavier Carrasco MODULE_DEVICE_TABLE(i2c, cc2_id);
7913af35092SJavier Carrasco 
7923af35092SJavier Carrasco static const struct of_device_id cc2_of_match[] = {
7933af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d23" },
7943af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d23s" },
7953af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d25" },
7963af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d25s" },
7973af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d33" },
7983af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d33s" },
7993af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d35" },
8003af35092SJavier Carrasco 	{ .compatible = "amphenol,cc2d35s" },
8013af35092SJavier Carrasco 	{ },
8023af35092SJavier Carrasco };
8033af35092SJavier Carrasco MODULE_DEVICE_TABLE(of, cc2_of_match);
8043af35092SJavier Carrasco 
8053af35092SJavier Carrasco static struct i2c_driver cc2_driver = {
8063af35092SJavier Carrasco 	.driver = {
8073af35092SJavier Carrasco 		.name	= "cc2d23",
8083af35092SJavier Carrasco 		.of_match_table = cc2_of_match,
8093af35092SJavier Carrasco 	},
8103af35092SJavier Carrasco 	.probe		= cc2_probe,
8113af35092SJavier Carrasco 	.remove		= cc2_remove,
8123af35092SJavier Carrasco 	.id_table = cc2_id,
8133af35092SJavier Carrasco };
8143af35092SJavier Carrasco module_i2c_driver(cc2_driver);
8153af35092SJavier Carrasco 
8163af35092SJavier Carrasco MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gamil.com>");
8173af35092SJavier Carrasco MODULE_DESCRIPTION("Amphenol ChipCap 2 humidity and temperature sensor driver");
8183af35092SJavier Carrasco MODULE_LICENSE("GPL");
819