Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6bd5878 authored by Guenter Roeck's avatar Guenter Roeck
Browse files

hwmon: (nct6775) Add case open detection

parent 9de2e2e8
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 * Super-I/O constants and functions
 */

#define NCT6775_LD_ACPI		0x0a
#define NCT6775_LD_HWM		0x0b
#define NCT6775_LD_VID		0x0d

@@ -186,6 +187,11 @@ static const s8 NCT6775_ALARM_BITS[] = {
	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
	12, -1 };			/* intrusion0, intrusion1 */

#define INTRUSION_ALARM_BASE	30

static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };

/* NCT6776 specific data */

static const s8 NCT6776_ALARM_BITS[] = {
@@ -694,6 +700,56 @@ show_vid(struct device *dev, struct device_attribute *attr, char *buf)

static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);

/* Case open detection */

static ssize_t
clear_caseopen(struct device *dev, struct device_attribute *attr,
	       const char *buf, size_t count)
{
	struct nct6775_data *data = dev_get_drvdata(dev);
	struct nct6775_sio_data *sio_data = dev->platform_data;
	int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
	unsigned long val;
	u8 reg;
	int ret;

	if (kstrtoul(buf, 10, &val) || val != 0)
		return -EINVAL;

	mutex_lock(&data->update_lock);

	/*
	 * Use CR registers to clear caseopen status.
	 * The CR registers are the same for all chips, and not all chips
	 * support clearing the caseopen status through "regular" registers.
	 */
	ret = superio_enter(sio_data->sioreg);
	if (ret) {
		count = ret;
		goto error;
	}

	superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
	reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
	reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
	superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
	reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
	superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
	superio_exit(sio_data->sioreg);

	data->valid = false;	/* Force cache refresh */
error:
	mutex_unlock(&data->update_lock);
	return count;
}

static struct sensor_device_attribute sda_caseopen[] = {
	SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
		    clear_caseopen, INTRUSION_ALARM_BASE),
	SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
		    clear_caseopen, INTRUSION_ALARM_BASE + 1),
};

/*
 * Driver and device management
 */
@@ -710,6 +766,9 @@ static void nct6775_device_remove_files(struct device *dev)
	for (i = 0; i < data->in_num; i++)
		sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);

	device_remove_file(dev, &sda_caseopen[0].dev_attr);
	device_remove_file(dev, &sda_caseopen[1].dev_attr);

	device_remove_file(dev, &dev_attr_name);
	device_remove_file(dev, &dev_attr_cpu0_vid);
}
@@ -828,6 +887,14 @@ static int nct6775_probe(struct platform_device *pdev)
			goto exit_remove;
	}

	for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
		if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
			continue;
		err = device_create_file(dev, &sda_caseopen[i].dev_attr);
		if (err)
			goto exit_remove;
	}

	err = device_create_file(dev, &dev_attr_name);
	if (err)
		goto exit_remove;