xref: /openbmc/linux/drivers/hwmon/pcf8591.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fb4504feSJean Delvare /*
357256088SGuenter Roeck  * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
457256088SGuenter Roeck  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
57c81c60fSJean Delvare  * the help of Jean Delvare <jdelvare@suse.de>
6fb4504feSJean Delvare  */
7fb4504feSJean Delvare 
82caec134SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
92caec134SJoe Perches 
10fb4504feSJean Delvare #include <linux/module.h>
11fb4504feSJean Delvare #include <linux/init.h>
12fb4504feSJean Delvare #include <linux/slab.h>
13fb4504feSJean Delvare #include <linux/i2c.h>
14fb4504feSJean Delvare #include <linux/mutex.h>
154275fcd6SJean Delvare #include <linux/err.h>
164275fcd6SJean Delvare #include <linux/hwmon.h>
1725f98688SChristophe JAILLET #include <linux/kstrtox.h>
18fb4504feSJean Delvare 
19fb4504feSJean Delvare /* Insmod parameters */
20fb4504feSJean Delvare 
21fb4504feSJean Delvare static int input_mode;
22fb4504feSJean Delvare module_param(input_mode, int, 0);
23fb4504feSJean Delvare MODULE_PARM_DESC(input_mode,
24fb4504feSJean Delvare 	"Analog input mode:\n"
25fb4504feSJean Delvare 	" 0 = four single ended inputs\n"
26fb4504feSJean Delvare 	" 1 = three differential inputs\n"
27fb4504feSJean Delvare 	" 2 = single ended and differential mixed\n"
28fb4504feSJean Delvare 	" 3 = two differential inputs\n");
29fb4504feSJean Delvare 
3057256088SGuenter Roeck /*
3157256088SGuenter Roeck  * The PCF8591 control byte
3257256088SGuenter Roeck  *      7    6    5    4    3    2    1    0
3357256088SGuenter Roeck  *   |  0 |AOEF|   AIP   |  0 |AINC|  AICH   |
3457256088SGuenter Roeck  */
35fb4504feSJean Delvare 
36fb4504feSJean Delvare /* Analog Output Enable Flag (analog output active if 1) */
37fb4504feSJean Delvare #define PCF8591_CONTROL_AOEF		0x40
38fb4504feSJean Delvare 
3957256088SGuenter Roeck /*
4057256088SGuenter Roeck  * Analog Input Programming
4157256088SGuenter Roeck  * 0x00 = four single ended inputs
4257256088SGuenter Roeck  * 0x10 = three differential inputs
4357256088SGuenter Roeck  * 0x20 = single ended and differential mixed
4457256088SGuenter Roeck  * 0x30 = two differential inputs
4557256088SGuenter Roeck  */
46fb4504feSJean Delvare #define PCF8591_CONTROL_AIP_MASK	0x30
47fb4504feSJean Delvare 
48fb4504feSJean Delvare /* Autoincrement Flag (switch on if 1) */
49fb4504feSJean Delvare #define PCF8591_CONTROL_AINC		0x04
50fb4504feSJean Delvare 
5157256088SGuenter Roeck /*
5257256088SGuenter Roeck  * Channel selection
5357256088SGuenter Roeck  * 0x00 = channel 0
5457256088SGuenter Roeck  * 0x01 = channel 1
5557256088SGuenter Roeck  * 0x02 = channel 2
5657256088SGuenter Roeck  * 0x03 = channel 3
5757256088SGuenter Roeck  */
58fb4504feSJean Delvare #define PCF8591_CONTROL_AICH_MASK	0x03
59fb4504feSJean Delvare 
60fb4504feSJean Delvare /* Initial values */
61fb4504feSJean Delvare #define PCF8591_INIT_CONTROL	((input_mode << 4) | PCF8591_CONTROL_AOEF)
62fb4504feSJean Delvare #define PCF8591_INIT_AOUT	0	/* DAC out = 0 */
63fb4504feSJean Delvare 
64fb4504feSJean Delvare /* Conversions */
65fb4504feSJean Delvare #define REG_TO_SIGNED(reg)	(((reg) & 0x80) ? ((reg) - 256) : (reg))
66fb4504feSJean Delvare 
67fb4504feSJean Delvare struct pcf8591_data {
684275fcd6SJean Delvare 	struct device *hwmon_dev;
69fb4504feSJean Delvare 	struct mutex update_lock;
70fb4504feSJean Delvare 
71fb4504feSJean Delvare 	u8 control;
72fb4504feSJean Delvare 	u8 aout;
73fb4504feSJean Delvare };
74fb4504feSJean Delvare 
75fb4504feSJean Delvare static void pcf8591_init_client(struct i2c_client *client);
76fb4504feSJean Delvare static int pcf8591_read_channel(struct device *dev, int channel);
77fb4504feSJean Delvare 
78fb4504feSJean Delvare /* following are the sysfs callback functions */
79fb4504feSJean Delvare #define show_in_channel(channel)					\
8057256088SGuenter Roeck static ssize_t show_in##channel##_input(struct device *dev,		\
8157256088SGuenter Roeck 					struct device_attribute *attr,	\
8257256088SGuenter Roeck 					char *buf)			\
83fb4504feSJean Delvare {									\
84fb4504feSJean Delvare 	return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\
85fb4504feSJean Delvare }									\
86fb4504feSJean Delvare static DEVICE_ATTR(in##channel##_input, S_IRUGO,			\
87fb4504feSJean Delvare 		   show_in##channel##_input, NULL);
88fb4504feSJean Delvare 
89fb4504feSJean Delvare show_in_channel(0);
90fb4504feSJean Delvare show_in_channel(1);
91fb4504feSJean Delvare show_in_channel(2);
92fb4504feSJean Delvare show_in_channel(3);
93fb4504feSJean Delvare 
out0_output_show(struct device * dev,struct device_attribute * attr,char * buf)94309c675eSJulia Lawall static ssize_t out0_output_show(struct device *dev,
9557256088SGuenter Roeck 				struct device_attribute *attr, char *buf)
96fb4504feSJean Delvare {
97fb4504feSJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
98fb4504feSJean Delvare 	return sprintf(buf, "%d\n", data->aout * 10);
99fb4504feSJean Delvare }
100fb4504feSJean Delvare 
out0_output_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)101309c675eSJulia Lawall static ssize_t out0_output_store(struct device *dev,
10257256088SGuenter Roeck 				 struct device_attribute *attr,
10357256088SGuenter Roeck 				 const char *buf, size_t count)
104fb4504feSJean Delvare {
10557256088SGuenter Roeck 	unsigned long val;
106fb4504feSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
107fb4504feSJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(client);
10857256088SGuenter Roeck 	int err;
10957256088SGuenter Roeck 
11057256088SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
11157256088SGuenter Roeck 	if (err)
11257256088SGuenter Roeck 		return err;
11357256088SGuenter Roeck 
11457256088SGuenter Roeck 	val /= 10;
11557256088SGuenter Roeck 	if (val > 255)
11657256088SGuenter Roeck 		return -EINVAL;
11757256088SGuenter Roeck 
11857256088SGuenter Roeck 	data->aout = val;
119fb4504feSJean Delvare 	i2c_smbus_write_byte_data(client, data->control, data->aout);
120fb4504feSJean Delvare 	return count;
121fb4504feSJean Delvare }
122fb4504feSJean Delvare 
123309c675eSJulia Lawall static DEVICE_ATTR_RW(out0_output);
124fb4504feSJean Delvare 
out0_enable_show(struct device * dev,struct device_attribute * attr,char * buf)125309c675eSJulia Lawall static ssize_t out0_enable_show(struct device *dev,
12657256088SGuenter Roeck 				struct device_attribute *attr, char *buf)
127fb4504feSJean Delvare {
128fb4504feSJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
129fb4504feSJean Delvare 	return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF)));
130fb4504feSJean Delvare }
131fb4504feSJean Delvare 
out0_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)132309c675eSJulia Lawall static ssize_t out0_enable_store(struct device *dev,
13357256088SGuenter Roeck 				 struct device_attribute *attr,
13457256088SGuenter Roeck 				 const char *buf, size_t count)
135fb4504feSJean Delvare {
136fb4504feSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
137fb4504feSJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(client);
13857256088SGuenter Roeck 	unsigned long val;
13957256088SGuenter Roeck 	int err;
14057256088SGuenter Roeck 
14157256088SGuenter Roeck 	err = kstrtoul(buf, 10, &val);
14257256088SGuenter Roeck 	if (err)
14357256088SGuenter Roeck 		return err;
144fb4504feSJean Delvare 
145fb4504feSJean Delvare 	mutex_lock(&data->update_lock);
146fb4504feSJean Delvare 	if (val)
147fb4504feSJean Delvare 		data->control |= PCF8591_CONTROL_AOEF;
148fb4504feSJean Delvare 	else
149fb4504feSJean Delvare 		data->control &= ~PCF8591_CONTROL_AOEF;
150fb4504feSJean Delvare 	i2c_smbus_write_byte(client, data->control);
151fb4504feSJean Delvare 	mutex_unlock(&data->update_lock);
152fb4504feSJean Delvare 	return count;
153fb4504feSJean Delvare }
154fb4504feSJean Delvare 
155309c675eSJulia Lawall static DEVICE_ATTR_RW(out0_enable);
156fb4504feSJean Delvare 
157fb4504feSJean Delvare static struct attribute *pcf8591_attributes[] = {
158fb4504feSJean Delvare 	&dev_attr_out0_enable.attr,
159fb4504feSJean Delvare 	&dev_attr_out0_output.attr,
160fb4504feSJean Delvare 	&dev_attr_in0_input.attr,
161fb4504feSJean Delvare 	&dev_attr_in1_input.attr,
162fb4504feSJean Delvare 	NULL
163fb4504feSJean Delvare };
164fb4504feSJean Delvare 
165fb4504feSJean Delvare static const struct attribute_group pcf8591_attr_group = {
166fb4504feSJean Delvare 	.attrs = pcf8591_attributes,
167fb4504feSJean Delvare };
168fb4504feSJean Delvare 
169fb4504feSJean Delvare static struct attribute *pcf8591_attributes_opt[] = {
170fb4504feSJean Delvare 	&dev_attr_in2_input.attr,
171fb4504feSJean Delvare 	&dev_attr_in3_input.attr,
172fb4504feSJean Delvare 	NULL
173fb4504feSJean Delvare };
174fb4504feSJean Delvare 
175fb4504feSJean Delvare static const struct attribute_group pcf8591_attr_group_opt = {
176fb4504feSJean Delvare 	.attrs = pcf8591_attributes_opt,
177fb4504feSJean Delvare };
178fb4504feSJean Delvare 
179fb4504feSJean Delvare /*
180fb4504feSJean Delvare  * Real code
181fb4504feSJean Delvare  */
182fb4504feSJean Delvare 
pcf8591_probe(struct i2c_client * client)18367487038SStephen Kitt static int pcf8591_probe(struct i2c_client *client)
184fb4504feSJean Delvare {
185fb4504feSJean Delvare 	struct pcf8591_data *data;
186fb4504feSJean Delvare 	int err;
187fb4504feSJean Delvare 
18860c2b569SGuenter Roeck 	data = devm_kzalloc(&client->dev, sizeof(struct pcf8591_data),
18960c2b569SGuenter Roeck 			    GFP_KERNEL);
19060c2b569SGuenter Roeck 	if (!data)
19160c2b569SGuenter Roeck 		return -ENOMEM;
192fb4504feSJean Delvare 
193fb4504feSJean Delvare 	i2c_set_clientdata(client, data);
194fb4504feSJean Delvare 	mutex_init(&data->update_lock);
195fb4504feSJean Delvare 
196fb4504feSJean Delvare 	/* Initialize the PCF8591 chip */
197fb4504feSJean Delvare 	pcf8591_init_client(client);
198fb4504feSJean Delvare 
199fb4504feSJean Delvare 	/* Register sysfs hooks */
200fb4504feSJean Delvare 	err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
201fb4504feSJean Delvare 	if (err)
20260c2b569SGuenter Roeck 		return err;
203fb4504feSJean Delvare 
204fb4504feSJean Delvare 	/* Register input2 if not in "two differential inputs" mode */
205fb4504feSJean Delvare 	if (input_mode != 3) {
20657256088SGuenter Roeck 		err = device_create_file(&client->dev, &dev_attr_in2_input);
20757256088SGuenter Roeck 		if (err)
208fb4504feSJean Delvare 			goto exit_sysfs_remove;
209fb4504feSJean Delvare 	}
210fb4504feSJean Delvare 
211fb4504feSJean Delvare 	/* Register input3 only in "four single ended inputs" mode */
212fb4504feSJean Delvare 	if (input_mode == 0) {
21357256088SGuenter Roeck 		err = device_create_file(&client->dev, &dev_attr_in3_input);
21457256088SGuenter Roeck 		if (err)
215fb4504feSJean Delvare 			goto exit_sysfs_remove;
216fb4504feSJean Delvare 	}
217fb4504feSJean Delvare 
2184275fcd6SJean Delvare 	data->hwmon_dev = hwmon_device_register(&client->dev);
2194275fcd6SJean Delvare 	if (IS_ERR(data->hwmon_dev)) {
2204275fcd6SJean Delvare 		err = PTR_ERR(data->hwmon_dev);
2214275fcd6SJean Delvare 		goto exit_sysfs_remove;
2224275fcd6SJean Delvare 	}
2234275fcd6SJean Delvare 
224fb4504feSJean Delvare 	return 0;
225fb4504feSJean Delvare 
226fb4504feSJean Delvare exit_sysfs_remove:
227fb4504feSJean Delvare 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
228fb4504feSJean Delvare 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
229fb4504feSJean Delvare 	return err;
230fb4504feSJean Delvare }
231fb4504feSJean Delvare 
pcf8591_remove(struct i2c_client * client)232ed5c2f5fSUwe Kleine-König static void pcf8591_remove(struct i2c_client *client)
233fb4504feSJean Delvare {
2344275fcd6SJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(client);
2354275fcd6SJean Delvare 
2364275fcd6SJean Delvare 	hwmon_device_unregister(data->hwmon_dev);
237fb4504feSJean Delvare 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
238fb4504feSJean Delvare 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
239fb4504feSJean Delvare }
240fb4504feSJean Delvare 
241fb4504feSJean Delvare /* Called when we have found a new PCF8591. */
pcf8591_init_client(struct i2c_client * client)242fb4504feSJean Delvare static void pcf8591_init_client(struct i2c_client *client)
243fb4504feSJean Delvare {
244fb4504feSJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(client);
245fb4504feSJean Delvare 	data->control = PCF8591_INIT_CONTROL;
246fb4504feSJean Delvare 	data->aout = PCF8591_INIT_AOUT;
247fb4504feSJean Delvare 
248fb4504feSJean Delvare 	i2c_smbus_write_byte_data(client, data->control, data->aout);
249fb4504feSJean Delvare 
25057256088SGuenter Roeck 	/*
25157256088SGuenter Roeck 	 * The first byte transmitted contains the conversion code of the
25257256088SGuenter Roeck 	 * previous read cycle. FLUSH IT!
25357256088SGuenter Roeck 	 */
254fb4504feSJean Delvare 	i2c_smbus_read_byte(client);
255fb4504feSJean Delvare }
256fb4504feSJean Delvare 
pcf8591_read_channel(struct device * dev,int channel)257fb4504feSJean Delvare static int pcf8591_read_channel(struct device *dev, int channel)
258fb4504feSJean Delvare {
259fb4504feSJean Delvare 	u8 value;
260fb4504feSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
261fb4504feSJean Delvare 	struct pcf8591_data *data = i2c_get_clientdata(client);
262fb4504feSJean Delvare 
263fb4504feSJean Delvare 	mutex_lock(&data->update_lock);
264fb4504feSJean Delvare 
265fb4504feSJean Delvare 	if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) {
266fb4504feSJean Delvare 		data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
267fb4504feSJean Delvare 			      | channel;
268fb4504feSJean Delvare 		i2c_smbus_write_byte(client, data->control);
269fb4504feSJean Delvare 
27057256088SGuenter Roeck 		/*
27157256088SGuenter Roeck 		 * The first byte transmitted contains the conversion code of
27257256088SGuenter Roeck 		 * the previous read cycle. FLUSH IT!
27357256088SGuenter Roeck 		 */
274fb4504feSJean Delvare 		i2c_smbus_read_byte(client);
275fb4504feSJean Delvare 	}
276fb4504feSJean Delvare 	value = i2c_smbus_read_byte(client);
277fb4504feSJean Delvare 
278fb4504feSJean Delvare 	mutex_unlock(&data->update_lock);
279fb4504feSJean Delvare 
280fb4504feSJean Delvare 	if ((channel == 2 && input_mode == 2) ||
281fb4504feSJean Delvare 	    (channel != 3 && (input_mode == 1 || input_mode == 3)))
2827fe83ad8SFrans Meulenbroeks 		return 10 * REG_TO_SIGNED(value);
283fb4504feSJean Delvare 	else
2847fe83ad8SFrans Meulenbroeks 		return 10 * value;
285fb4504feSJean Delvare }
286fb4504feSJean Delvare 
287fb4504feSJean Delvare static const struct i2c_device_id pcf8591_id[] = {
288fb4504feSJean Delvare 	{ "pcf8591", 0 },
289fb4504feSJean Delvare 	{ }
290fb4504feSJean Delvare };
291fb4504feSJean Delvare MODULE_DEVICE_TABLE(i2c, pcf8591_id);
292fb4504feSJean Delvare 
293fb4504feSJean Delvare static struct i2c_driver pcf8591_driver = {
294fb4504feSJean Delvare 	.driver = {
295fb4504feSJean Delvare 		.name	= "pcf8591",
296fb4504feSJean Delvare 	},
297*1975d167SUwe Kleine-König 	.probe		= pcf8591_probe,
298fb4504feSJean Delvare 	.remove		= pcf8591_remove,
299fb4504feSJean Delvare 	.id_table	= pcf8591_id,
300fb4504feSJean Delvare };
301fb4504feSJean Delvare 
pcf8591_init(void)302fb4504feSJean Delvare static int __init pcf8591_init(void)
303fb4504feSJean Delvare {
304fb4504feSJean Delvare 	if (input_mode < 0 || input_mode > 3) {
3052caec134SJoe Perches 		pr_warn("invalid input_mode (%d)\n", input_mode);
306fb4504feSJean Delvare 		input_mode = 0;
307fb4504feSJean Delvare 	}
308fb4504feSJean Delvare 	return i2c_add_driver(&pcf8591_driver);
309fb4504feSJean Delvare }
310fb4504feSJean Delvare 
pcf8591_exit(void)311fb4504feSJean Delvare static void __exit pcf8591_exit(void)
312fb4504feSJean Delvare {
313fb4504feSJean Delvare 	i2c_del_driver(&pcf8591_driver);
314fb4504feSJean Delvare }
315fb4504feSJean Delvare 
316fb4504feSJean Delvare MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
317fb4504feSJean Delvare MODULE_DESCRIPTION("PCF8591 driver");
318fb4504feSJean Delvare MODULE_LICENSE("GPL");
319fb4504feSJean Delvare 
320fb4504feSJean Delvare module_init(pcf8591_init);
321fb4504feSJean Delvare module_exit(pcf8591_exit);
322