xref: /OK3568_Linux_fs/kernel/drivers/hwmon/sch5627.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /***************************************************************************
3*4882a593Smuzhiyun  *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *
4*4882a593Smuzhiyun  *                                                                         *
5*4882a593Smuzhiyun  ***************************************************************************/
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/jiffies.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/hwmon.h>
15*4882a593Smuzhiyun #include <linux/hwmon-sysfs.h>
16*4882a593Smuzhiyun #include <linux/err.h>
17*4882a593Smuzhiyun #include <linux/mutex.h>
18*4882a593Smuzhiyun #include "sch56xx-common.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define DRVNAME "sch5627"
21*4882a593Smuzhiyun #define DEVNAME DRVNAME /* We only support one model */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define SCH5627_HWMON_ID		0xa5
24*4882a593Smuzhiyun #define SCH5627_COMPANY_ID		0x5c
25*4882a593Smuzhiyun #define SCH5627_PRIMARY_ID		0xa0
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define SCH5627_REG_BUILD_CODE		0x39
28*4882a593Smuzhiyun #define SCH5627_REG_BUILD_ID		0x3a
29*4882a593Smuzhiyun #define SCH5627_REG_HWMON_ID		0x3c
30*4882a593Smuzhiyun #define SCH5627_REG_HWMON_REV		0x3d
31*4882a593Smuzhiyun #define SCH5627_REG_COMPANY_ID		0x3e
32*4882a593Smuzhiyun #define SCH5627_REG_PRIMARY_ID		0x3f
33*4882a593Smuzhiyun #define SCH5627_REG_CTRL		0x40
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define SCH5627_NO_TEMPS		8
36*4882a593Smuzhiyun #define SCH5627_NO_FANS			4
37*4882a593Smuzhiyun #define SCH5627_NO_IN			5
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {
40*4882a593Smuzhiyun 	0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };
41*4882a593Smuzhiyun static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {
42*4882a593Smuzhiyun 	0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };
43*4882a593Smuzhiyun static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {
44*4882a593Smuzhiyun 	0, 0, 1, 1, 0, 0, 0, 1 };
45*4882a593Smuzhiyun static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {
46*4882a593Smuzhiyun 	0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };
47*4882a593Smuzhiyun static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {
48*4882a593Smuzhiyun 	0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
51*4882a593Smuzhiyun 	0x2C, 0x2E, 0x30, 0x32 };
52*4882a593Smuzhiyun static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
53*4882a593Smuzhiyun 	0x62, 0x64, 0x66, 0x68 };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
56*4882a593Smuzhiyun 	0x22, 0x23, 0x24, 0x25, 0x189 };
57*4882a593Smuzhiyun static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
58*4882a593Smuzhiyun 	0xE4, 0xE4, 0xE3, 0xE3, 0x18A };
59*4882a593Smuzhiyun static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {
60*4882a593Smuzhiyun 	1, 0, 1, 0, 1 };
61*4882a593Smuzhiyun static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {
62*4882a593Smuzhiyun 	10745, 3660, 9765, 10745, 3660 };
63*4882a593Smuzhiyun static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
64*4882a593Smuzhiyun 	"VCC", "VTT", "VBAT", "VTR", "V_IN" };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun struct sch5627_data {
67*4882a593Smuzhiyun 	unsigned short addr;
68*4882a593Smuzhiyun 	struct device *hwmon_dev;
69*4882a593Smuzhiyun 	struct sch56xx_watchdog_data *watchdog;
70*4882a593Smuzhiyun 	u8 control;
71*4882a593Smuzhiyun 	u8 temp_max[SCH5627_NO_TEMPS];
72*4882a593Smuzhiyun 	u8 temp_crit[SCH5627_NO_TEMPS];
73*4882a593Smuzhiyun 	u16 fan_min[SCH5627_NO_FANS];
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	struct mutex update_lock;
76*4882a593Smuzhiyun 	unsigned long last_battery;	/* In jiffies */
77*4882a593Smuzhiyun 	char valid;			/* !=0 if following fields are valid */
78*4882a593Smuzhiyun 	unsigned long last_updated;	/* In jiffies */
79*4882a593Smuzhiyun 	u16 temp[SCH5627_NO_TEMPS];
80*4882a593Smuzhiyun 	u16 fan[SCH5627_NO_FANS];
81*4882a593Smuzhiyun 	u16 in[SCH5627_NO_IN];
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
sch5627_update_device(struct device * dev)84*4882a593Smuzhiyun static struct sch5627_data *sch5627_update_device(struct device *dev)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	struct sch5627_data *data = dev_get_drvdata(dev);
87*4882a593Smuzhiyun 	struct sch5627_data *ret = data;
88*4882a593Smuzhiyun 	int i, val;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	mutex_lock(&data->update_lock);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* Trigger a Vbat voltage measurement every 5 minutes */
93*4882a593Smuzhiyun 	if (time_after(jiffies, data->last_battery + 300 * HZ)) {
94*4882a593Smuzhiyun 		sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
95*4882a593Smuzhiyun 					  data->control | 0x10);
96*4882a593Smuzhiyun 		data->last_battery = jiffies;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	/* Cache the values for 1 second */
100*4882a593Smuzhiyun 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
101*4882a593Smuzhiyun 		for (i = 0; i < SCH5627_NO_TEMPS; i++) {
102*4882a593Smuzhiyun 			val = sch56xx_read_virtual_reg12(data->addr,
103*4882a593Smuzhiyun 				SCH5627_REG_TEMP_MSB[i],
104*4882a593Smuzhiyun 				SCH5627_REG_TEMP_LSN[i],
105*4882a593Smuzhiyun 				SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
106*4882a593Smuzhiyun 			if (unlikely(val < 0)) {
107*4882a593Smuzhiyun 				ret = ERR_PTR(val);
108*4882a593Smuzhiyun 				goto abort;
109*4882a593Smuzhiyun 			}
110*4882a593Smuzhiyun 			data->temp[i] = val;
111*4882a593Smuzhiyun 		}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		for (i = 0; i < SCH5627_NO_FANS; i++) {
114*4882a593Smuzhiyun 			val = sch56xx_read_virtual_reg16(data->addr,
115*4882a593Smuzhiyun 							 SCH5627_REG_FAN[i]);
116*4882a593Smuzhiyun 			if (unlikely(val < 0)) {
117*4882a593Smuzhiyun 				ret = ERR_PTR(val);
118*4882a593Smuzhiyun 				goto abort;
119*4882a593Smuzhiyun 			}
120*4882a593Smuzhiyun 			data->fan[i] = val;
121*4882a593Smuzhiyun 		}
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		for (i = 0; i < SCH5627_NO_IN; i++) {
124*4882a593Smuzhiyun 			val = sch56xx_read_virtual_reg12(data->addr,
125*4882a593Smuzhiyun 				SCH5627_REG_IN_MSB[i],
126*4882a593Smuzhiyun 				SCH5627_REG_IN_LSN[i],
127*4882a593Smuzhiyun 				SCH5627_REG_IN_HIGH_NIBBLE[i]);
128*4882a593Smuzhiyun 			if (unlikely(val < 0)) {
129*4882a593Smuzhiyun 				ret = ERR_PTR(val);
130*4882a593Smuzhiyun 				goto abort;
131*4882a593Smuzhiyun 			}
132*4882a593Smuzhiyun 			data->in[i] = val;
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		data->last_updated = jiffies;
136*4882a593Smuzhiyun 		data->valid = 1;
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun abort:
139*4882a593Smuzhiyun 	mutex_unlock(&data->update_lock);
140*4882a593Smuzhiyun 	return ret;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
sch5627_read_limits(struct sch5627_data * data)143*4882a593Smuzhiyun static int sch5627_read_limits(struct sch5627_data *data)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	int i, val;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	for (i = 0; i < SCH5627_NO_TEMPS; i++) {
148*4882a593Smuzhiyun 		/*
149*4882a593Smuzhiyun 		 * Note what SMSC calls ABS, is what lm_sensors calls max
150*4882a593Smuzhiyun 		 * (aka high), and HIGH is what lm_sensors calls crit.
151*4882a593Smuzhiyun 		 */
152*4882a593Smuzhiyun 		val = sch56xx_read_virtual_reg(data->addr,
153*4882a593Smuzhiyun 					       SCH5627_REG_TEMP_ABS[i]);
154*4882a593Smuzhiyun 		if (val < 0)
155*4882a593Smuzhiyun 			return val;
156*4882a593Smuzhiyun 		data->temp_max[i] = val;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		val = sch56xx_read_virtual_reg(data->addr,
159*4882a593Smuzhiyun 					       SCH5627_REG_TEMP_HIGH[i]);
160*4882a593Smuzhiyun 		if (val < 0)
161*4882a593Smuzhiyun 			return val;
162*4882a593Smuzhiyun 		data->temp_crit[i] = val;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 	for (i = 0; i < SCH5627_NO_FANS; i++) {
165*4882a593Smuzhiyun 		val = sch56xx_read_virtual_reg16(data->addr,
166*4882a593Smuzhiyun 						 SCH5627_REG_FAN_MIN[i]);
167*4882a593Smuzhiyun 		if (val < 0)
168*4882a593Smuzhiyun 			return val;
169*4882a593Smuzhiyun 		data->fan_min[i] = val;
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
reg_to_temp(u16 reg)175*4882a593Smuzhiyun static int reg_to_temp(u16 reg)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	return (reg * 625) / 10 - 64000;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
reg_to_temp_limit(u8 reg)180*4882a593Smuzhiyun static int reg_to_temp_limit(u8 reg)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	return (reg - 64) * 1000;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
reg_to_rpm(u16 reg)185*4882a593Smuzhiyun static int reg_to_rpm(u16 reg)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	if (reg == 0)
188*4882a593Smuzhiyun 		return -EIO;
189*4882a593Smuzhiyun 	if (reg == 0xffff)
190*4882a593Smuzhiyun 		return 0;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return 5400540 / reg;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
name_show(struct device * dev,struct device_attribute * devattr,char * buf)195*4882a593Smuzhiyun static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
196*4882a593Smuzhiyun 	char *buf)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
temp_show(struct device * dev,struct device_attribute * devattr,char * buf)201*4882a593Smuzhiyun static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
202*4882a593Smuzhiyun 			 char *buf)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
205*4882a593Smuzhiyun 	struct sch5627_data *data = sch5627_update_device(dev);
206*4882a593Smuzhiyun 	int val;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if (IS_ERR(data))
209*4882a593Smuzhiyun 		return PTR_ERR(data);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	val = reg_to_temp(data->temp[attr->index]);
212*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
temp_fault_show(struct device * dev,struct device_attribute * devattr,char * buf)215*4882a593Smuzhiyun static ssize_t temp_fault_show(struct device *dev,
216*4882a593Smuzhiyun 			       struct device_attribute *devattr, char *buf)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
219*4882a593Smuzhiyun 	struct sch5627_data *data = sch5627_update_device(dev);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if (IS_ERR(data))
222*4882a593Smuzhiyun 		return PTR_ERR(data);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
temp_max_show(struct device * dev,struct device_attribute * devattr,char * buf)227*4882a593Smuzhiyun static ssize_t temp_max_show(struct device *dev,
228*4882a593Smuzhiyun 			     struct device_attribute *devattr, char *buf)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
231*4882a593Smuzhiyun 	struct sch5627_data *data = dev_get_drvdata(dev);
232*4882a593Smuzhiyun 	int val;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	val = reg_to_temp_limit(data->temp_max[attr->index]);
235*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
temp_crit_show(struct device * dev,struct device_attribute * devattr,char * buf)238*4882a593Smuzhiyun static ssize_t temp_crit_show(struct device *dev,
239*4882a593Smuzhiyun 			      struct device_attribute *devattr, char *buf)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
242*4882a593Smuzhiyun 	struct sch5627_data *data = dev_get_drvdata(dev);
243*4882a593Smuzhiyun 	int val;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	val = reg_to_temp_limit(data->temp_crit[attr->index]);
246*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
fan_show(struct device * dev,struct device_attribute * devattr,char * buf)249*4882a593Smuzhiyun static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
250*4882a593Smuzhiyun 			char *buf)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
253*4882a593Smuzhiyun 	struct sch5627_data *data = sch5627_update_device(dev);
254*4882a593Smuzhiyun 	int val;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (IS_ERR(data))
257*4882a593Smuzhiyun 		return PTR_ERR(data);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	val = reg_to_rpm(data->fan[attr->index]);
260*4882a593Smuzhiyun 	if (val < 0)
261*4882a593Smuzhiyun 		return val;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
fan_fault_show(struct device * dev,struct device_attribute * devattr,char * buf)266*4882a593Smuzhiyun static ssize_t fan_fault_show(struct device *dev,
267*4882a593Smuzhiyun 			      struct device_attribute *devattr, char *buf)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
270*4882a593Smuzhiyun 	struct sch5627_data *data = sch5627_update_device(dev);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (IS_ERR(data))
273*4882a593Smuzhiyun 		return PTR_ERR(data);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n",
276*4882a593Smuzhiyun 			data->fan[attr->index] == 0xffff);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
fan_min_show(struct device * dev,struct device_attribute * devattr,char * buf)279*4882a593Smuzhiyun static ssize_t fan_min_show(struct device *dev,
280*4882a593Smuzhiyun 			    struct device_attribute *devattr, char *buf)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
283*4882a593Smuzhiyun 	struct sch5627_data *data = dev_get_drvdata(dev);
284*4882a593Smuzhiyun 	int val = reg_to_rpm(data->fan_min[attr->index]);
285*4882a593Smuzhiyun 	if (val < 0)
286*4882a593Smuzhiyun 		return val;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
in_show(struct device * dev,struct device_attribute * devattr,char * buf)291*4882a593Smuzhiyun static ssize_t in_show(struct device *dev, struct device_attribute *devattr,
292*4882a593Smuzhiyun 		       char *buf)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
295*4882a593Smuzhiyun 	struct sch5627_data *data = sch5627_update_device(dev);
296*4882a593Smuzhiyun 	int val;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (IS_ERR(data))
299*4882a593Smuzhiyun 		return PTR_ERR(data);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	val = DIV_ROUND_CLOSEST(
302*4882a593Smuzhiyun 		data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index],
303*4882a593Smuzhiyun 		10000);
304*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
in_label_show(struct device * dev,struct device_attribute * devattr,char * buf)307*4882a593Smuzhiyun static ssize_t in_label_show(struct device *dev,
308*4882a593Smuzhiyun 			     struct device_attribute *devattr, char *buf)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%s\n",
313*4882a593Smuzhiyun 			SCH5627_IN_LABELS[attr->index]);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun static DEVICE_ATTR_RO(name);
317*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
318*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
319*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
320*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3);
321*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp5_input, temp, 4);
322*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp6_input, temp, 5);
323*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp7_input, temp, 6);
324*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp8_input, temp, 7);
325*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
326*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
327*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2);
328*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3);
329*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp5_fault, temp_fault, 4);
330*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp6_fault, temp_fault, 5);
331*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp7_fault, temp_fault, 6);
332*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp8_fault, temp_fault, 7);
333*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp1_max, temp_max, 0);
334*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp2_max, temp_max, 1);
335*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp3_max, temp_max, 2);
336*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp4_max, temp_max, 3);
337*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp5_max, temp_max, 4);
338*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp6_max, temp_max, 5);
339*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp7_max, temp_max, 6);
340*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp8_max, temp_max, 7);
341*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp1_crit, temp_crit, 0);
342*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp2_crit, temp_crit, 1);
343*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp3_crit, temp_crit, 2);
344*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp4_crit, temp_crit, 3);
345*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp5_crit, temp_crit, 4);
346*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp6_crit, temp_crit, 5);
347*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp7_crit, temp_crit, 6);
348*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(temp8_crit, temp_crit, 7);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
351*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
352*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
353*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
354*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan1_fault, fan_fault, 0);
355*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan2_fault, fan_fault, 1);
356*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan3_fault, fan_fault, 2);
357*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan4_fault, fan_fault, 3);
358*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan1_min, fan_min, 0);
359*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan2_min, fan_min, 1);
360*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan3_min, fan_min, 2);
361*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(fan4_min, fan_min, 3);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
364*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
365*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
366*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
367*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
368*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in0_label, in_label, 0);
369*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in1_label, in_label, 1);
370*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in2_label, in_label, 2);
371*4882a593Smuzhiyun static SENSOR_DEVICE_ATTR_RO(in3_label, in_label, 3);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun static struct attribute *sch5627_attributes[] = {
374*4882a593Smuzhiyun 	&dev_attr_name.attr,
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	&sensor_dev_attr_temp1_input.dev_attr.attr,
377*4882a593Smuzhiyun 	&sensor_dev_attr_temp2_input.dev_attr.attr,
378*4882a593Smuzhiyun 	&sensor_dev_attr_temp3_input.dev_attr.attr,
379*4882a593Smuzhiyun 	&sensor_dev_attr_temp4_input.dev_attr.attr,
380*4882a593Smuzhiyun 	&sensor_dev_attr_temp5_input.dev_attr.attr,
381*4882a593Smuzhiyun 	&sensor_dev_attr_temp6_input.dev_attr.attr,
382*4882a593Smuzhiyun 	&sensor_dev_attr_temp7_input.dev_attr.attr,
383*4882a593Smuzhiyun 	&sensor_dev_attr_temp8_input.dev_attr.attr,
384*4882a593Smuzhiyun 	&sensor_dev_attr_temp1_fault.dev_attr.attr,
385*4882a593Smuzhiyun 	&sensor_dev_attr_temp2_fault.dev_attr.attr,
386*4882a593Smuzhiyun 	&sensor_dev_attr_temp3_fault.dev_attr.attr,
387*4882a593Smuzhiyun 	&sensor_dev_attr_temp4_fault.dev_attr.attr,
388*4882a593Smuzhiyun 	&sensor_dev_attr_temp5_fault.dev_attr.attr,
389*4882a593Smuzhiyun 	&sensor_dev_attr_temp6_fault.dev_attr.attr,
390*4882a593Smuzhiyun 	&sensor_dev_attr_temp7_fault.dev_attr.attr,
391*4882a593Smuzhiyun 	&sensor_dev_attr_temp8_fault.dev_attr.attr,
392*4882a593Smuzhiyun 	&sensor_dev_attr_temp1_max.dev_attr.attr,
393*4882a593Smuzhiyun 	&sensor_dev_attr_temp2_max.dev_attr.attr,
394*4882a593Smuzhiyun 	&sensor_dev_attr_temp3_max.dev_attr.attr,
395*4882a593Smuzhiyun 	&sensor_dev_attr_temp4_max.dev_attr.attr,
396*4882a593Smuzhiyun 	&sensor_dev_attr_temp5_max.dev_attr.attr,
397*4882a593Smuzhiyun 	&sensor_dev_attr_temp6_max.dev_attr.attr,
398*4882a593Smuzhiyun 	&sensor_dev_attr_temp7_max.dev_attr.attr,
399*4882a593Smuzhiyun 	&sensor_dev_attr_temp8_max.dev_attr.attr,
400*4882a593Smuzhiyun 	&sensor_dev_attr_temp1_crit.dev_attr.attr,
401*4882a593Smuzhiyun 	&sensor_dev_attr_temp2_crit.dev_attr.attr,
402*4882a593Smuzhiyun 	&sensor_dev_attr_temp3_crit.dev_attr.attr,
403*4882a593Smuzhiyun 	&sensor_dev_attr_temp4_crit.dev_attr.attr,
404*4882a593Smuzhiyun 	&sensor_dev_attr_temp5_crit.dev_attr.attr,
405*4882a593Smuzhiyun 	&sensor_dev_attr_temp6_crit.dev_attr.attr,
406*4882a593Smuzhiyun 	&sensor_dev_attr_temp7_crit.dev_attr.attr,
407*4882a593Smuzhiyun 	&sensor_dev_attr_temp8_crit.dev_attr.attr,
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	&sensor_dev_attr_fan1_input.dev_attr.attr,
410*4882a593Smuzhiyun 	&sensor_dev_attr_fan2_input.dev_attr.attr,
411*4882a593Smuzhiyun 	&sensor_dev_attr_fan3_input.dev_attr.attr,
412*4882a593Smuzhiyun 	&sensor_dev_attr_fan4_input.dev_attr.attr,
413*4882a593Smuzhiyun 	&sensor_dev_attr_fan1_fault.dev_attr.attr,
414*4882a593Smuzhiyun 	&sensor_dev_attr_fan2_fault.dev_attr.attr,
415*4882a593Smuzhiyun 	&sensor_dev_attr_fan3_fault.dev_attr.attr,
416*4882a593Smuzhiyun 	&sensor_dev_attr_fan4_fault.dev_attr.attr,
417*4882a593Smuzhiyun 	&sensor_dev_attr_fan1_min.dev_attr.attr,
418*4882a593Smuzhiyun 	&sensor_dev_attr_fan2_min.dev_attr.attr,
419*4882a593Smuzhiyun 	&sensor_dev_attr_fan3_min.dev_attr.attr,
420*4882a593Smuzhiyun 	&sensor_dev_attr_fan4_min.dev_attr.attr,
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	&sensor_dev_attr_in0_input.dev_attr.attr,
423*4882a593Smuzhiyun 	&sensor_dev_attr_in1_input.dev_attr.attr,
424*4882a593Smuzhiyun 	&sensor_dev_attr_in2_input.dev_attr.attr,
425*4882a593Smuzhiyun 	&sensor_dev_attr_in3_input.dev_attr.attr,
426*4882a593Smuzhiyun 	&sensor_dev_attr_in4_input.dev_attr.attr,
427*4882a593Smuzhiyun 	&sensor_dev_attr_in0_label.dev_attr.attr,
428*4882a593Smuzhiyun 	&sensor_dev_attr_in1_label.dev_attr.attr,
429*4882a593Smuzhiyun 	&sensor_dev_attr_in2_label.dev_attr.attr,
430*4882a593Smuzhiyun 	&sensor_dev_attr_in3_label.dev_attr.attr,
431*4882a593Smuzhiyun 	/* No in4_label as in4 is a generic input pin */
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	NULL
434*4882a593Smuzhiyun };
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun static const struct attribute_group sch5627_group = {
437*4882a593Smuzhiyun 	.attrs = sch5627_attributes,
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun 
sch5627_remove(struct platform_device * pdev)440*4882a593Smuzhiyun static int sch5627_remove(struct platform_device *pdev)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun 	struct sch5627_data *data = platform_get_drvdata(pdev);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	if (data->watchdog)
445*4882a593Smuzhiyun 		sch56xx_watchdog_unregister(data->watchdog);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (data->hwmon_dev)
448*4882a593Smuzhiyun 		hwmon_device_unregister(data->hwmon_dev);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	return 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun 
sch5627_probe(struct platform_device * pdev)455*4882a593Smuzhiyun static int sch5627_probe(struct platform_device *pdev)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	struct sch5627_data *data;
458*4882a593Smuzhiyun 	int err, build_code, build_id, hwmon_rev, val;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
461*4882a593Smuzhiyun 			    GFP_KERNEL);
462*4882a593Smuzhiyun 	if (!data)
463*4882a593Smuzhiyun 		return -ENOMEM;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
466*4882a593Smuzhiyun 	mutex_init(&data->update_lock);
467*4882a593Smuzhiyun 	platform_set_drvdata(pdev, data);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID);
470*4882a593Smuzhiyun 	if (val < 0) {
471*4882a593Smuzhiyun 		err = val;
472*4882a593Smuzhiyun 		goto error;
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 	if (val != SCH5627_HWMON_ID) {
475*4882a593Smuzhiyun 		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
476*4882a593Smuzhiyun 		       val, SCH5627_HWMON_ID);
477*4882a593Smuzhiyun 		err = -ENODEV;
478*4882a593Smuzhiyun 		goto error;
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID);
482*4882a593Smuzhiyun 	if (val < 0) {
483*4882a593Smuzhiyun 		err = val;
484*4882a593Smuzhiyun 		goto error;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	if (val != SCH5627_COMPANY_ID) {
487*4882a593Smuzhiyun 		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
488*4882a593Smuzhiyun 		       val, SCH5627_COMPANY_ID);
489*4882a593Smuzhiyun 		err = -ENODEV;
490*4882a593Smuzhiyun 		goto error;
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID);
494*4882a593Smuzhiyun 	if (val < 0) {
495*4882a593Smuzhiyun 		err = val;
496*4882a593Smuzhiyun 		goto error;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 	if (val != SCH5627_PRIMARY_ID) {
499*4882a593Smuzhiyun 		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
500*4882a593Smuzhiyun 		       val, SCH5627_PRIMARY_ID);
501*4882a593Smuzhiyun 		err = -ENODEV;
502*4882a593Smuzhiyun 		goto error;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	build_code = sch56xx_read_virtual_reg(data->addr,
506*4882a593Smuzhiyun 					      SCH5627_REG_BUILD_CODE);
507*4882a593Smuzhiyun 	if (build_code < 0) {
508*4882a593Smuzhiyun 		err = build_code;
509*4882a593Smuzhiyun 		goto error;
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	build_id = sch56xx_read_virtual_reg16(data->addr,
513*4882a593Smuzhiyun 					      SCH5627_REG_BUILD_ID);
514*4882a593Smuzhiyun 	if (build_id < 0) {
515*4882a593Smuzhiyun 		err = build_id;
516*4882a593Smuzhiyun 		goto error;
517*4882a593Smuzhiyun 	}
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	hwmon_rev = sch56xx_read_virtual_reg(data->addr,
520*4882a593Smuzhiyun 					     SCH5627_REG_HWMON_REV);
521*4882a593Smuzhiyun 	if (hwmon_rev < 0) {
522*4882a593Smuzhiyun 		err = hwmon_rev;
523*4882a593Smuzhiyun 		goto error;
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL);
527*4882a593Smuzhiyun 	if (val < 0) {
528*4882a593Smuzhiyun 		err = val;
529*4882a593Smuzhiyun 		goto error;
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 	data->control = val;
532*4882a593Smuzhiyun 	if (!(data->control & 0x01)) {
533*4882a593Smuzhiyun 		pr_err("hardware monitoring not enabled\n");
534*4882a593Smuzhiyun 		err = -ENODEV;
535*4882a593Smuzhiyun 		goto error;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 	/* Trigger a Vbat voltage measurement, so that we get a valid reading
538*4882a593Smuzhiyun 	   the first time we read Vbat */
539*4882a593Smuzhiyun 	sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
540*4882a593Smuzhiyun 				  data->control | 0x10);
541*4882a593Smuzhiyun 	data->last_battery = jiffies;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/*
544*4882a593Smuzhiyun 	 * Read limits, we do this only once as reading a register on
545*4882a593Smuzhiyun 	 * the sch5627 is quite expensive (and they don't change).
546*4882a593Smuzhiyun 	 */
547*4882a593Smuzhiyun 	err = sch5627_read_limits(data);
548*4882a593Smuzhiyun 	if (err)
549*4882a593Smuzhiyun 		goto error;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);
552*4882a593Smuzhiyun 	pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
553*4882a593Smuzhiyun 		build_code, build_id, hwmon_rev);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	/* Register sysfs interface files */
556*4882a593Smuzhiyun 	err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group);
557*4882a593Smuzhiyun 	if (err)
558*4882a593Smuzhiyun 		goto error;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
561*4882a593Smuzhiyun 	if (IS_ERR(data->hwmon_dev)) {
562*4882a593Smuzhiyun 		err = PTR_ERR(data->hwmon_dev);
563*4882a593Smuzhiyun 		data->hwmon_dev = NULL;
564*4882a593Smuzhiyun 		goto error;
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Note failing to register the watchdog is not a fatal error */
568*4882a593Smuzhiyun 	data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
569*4882a593Smuzhiyun 			(build_code << 24) | (build_id << 8) | hwmon_rev,
570*4882a593Smuzhiyun 			&data->update_lock, 1);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	return 0;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun error:
575*4882a593Smuzhiyun 	sch5627_remove(pdev);
576*4882a593Smuzhiyun 	return err;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun static struct platform_driver sch5627_driver = {
580*4882a593Smuzhiyun 	.driver = {
581*4882a593Smuzhiyun 		.name	= DRVNAME,
582*4882a593Smuzhiyun 	},
583*4882a593Smuzhiyun 	.probe		= sch5627_probe,
584*4882a593Smuzhiyun 	.remove		= sch5627_remove,
585*4882a593Smuzhiyun };
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun module_platform_driver(sch5627_driver);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
590*4882a593Smuzhiyun MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
591*4882a593Smuzhiyun MODULE_LICENSE("GPL");
592