| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 |     Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 3 |     Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 |     the help of Jean Delvare <khali@linux-fr.org> | 
 | 5 |  | 
 | 6 |     This program is free software; you can redistribute it and/or modify | 
 | 7 |     it under the terms of the GNU General Public License as published by | 
 | 8 |     the Free Software Foundation; either version 2 of the License, or | 
 | 9 |     (at your option) any later version. | 
 | 10 |  | 
 | 11 |     This program is distributed in the hope that it will be useful, | 
 | 12 |     but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 13 |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 14 |     GNU General Public License for more details. | 
 | 15 |  | 
 | 16 |     You should have received a copy of the GNU General Public License | 
 | 17 |     along with this program; if not, write to the Free Software | 
 | 18 |     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
 | 19 | */ | 
 | 20 |  | 
| Joe Perches | 2caec13 | 2010-10-20 06:51:45 +0000 | [diff] [blame] | 21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 
 | 22 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | #include <linux/module.h> | 
 | 24 | #include <linux/init.h> | 
 | 25 | #include <linux/slab.h> | 
 | 26 | #include <linux/i2c.h> | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 27 | #include <linux/mutex.h> | 
| Jean Delvare | 4275fcd | 2010-10-28 20:31:49 +0200 | [diff] [blame] | 28 | #include <linux/err.h> | 
 | 29 | #include <linux/hwmon.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | /* Insmod parameters */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 |  | 
 | 33 | static int input_mode; | 
 | 34 | module_param(input_mode, int, 0); | 
 | 35 | MODULE_PARM_DESC(input_mode, | 
 | 36 | 	"Analog input mode:\n" | 
 | 37 | 	" 0 = four single ended inputs\n" | 
 | 38 | 	" 1 = three differential inputs\n" | 
 | 39 | 	" 2 = single ended and differential mixed\n" | 
 | 40 | 	" 3 = two differential inputs\n"); | 
 | 41 |  | 
 | 42 | /* The PCF8591 control byte | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 43 |       7    6    5    4    3    2    1    0 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 |    |  0 |AOEF|   AIP   |  0 |AINC|  AICH   | */ | 
 | 45 |  | 
 | 46 | /* Analog Output Enable Flag (analog output active if 1) */ | 
 | 47 | #define PCF8591_CONTROL_AOEF		0x40 | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 48 |  | 
 | 49 | /* Analog Input Programming | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 |    0x00 = four single ended inputs | 
 | 51 |    0x10 = three differential inputs | 
 | 52 |    0x20 = single ended and differential mixed | 
 | 53 |    0x30 = two differential inputs */ | 
 | 54 | #define PCF8591_CONTROL_AIP_MASK	0x30 | 
 | 55 |  | 
 | 56 | /* Autoincrement Flag (switch on if 1) */ | 
 | 57 | #define PCF8591_CONTROL_AINC		0x04 | 
 | 58 |  | 
 | 59 | /* Channel selection | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 60 |    0x00 = channel 0 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 |    0x01 = channel 1 | 
 | 62 |    0x02 = channel 2 | 
 | 63 |    0x03 = channel 3 */ | 
 | 64 | #define PCF8591_CONTROL_AICH_MASK	0x03 | 
 | 65 |  | 
 | 66 | /* Initial values */ | 
 | 67 | #define PCF8591_INIT_CONTROL	((input_mode << 4) | PCF8591_CONTROL_AOEF) | 
 | 68 | #define PCF8591_INIT_AOUT	0	/* DAC out = 0 */ | 
 | 69 |  | 
 | 70 | /* Conversions */ | 
 | 71 | #define REG_TO_SIGNED(reg)	(((reg) & 0x80)?((reg) - 256):(reg)) | 
 | 72 |  | 
 | 73 | struct pcf8591_data { | 
| Jean Delvare | 4275fcd | 2010-10-28 20:31:49 +0200 | [diff] [blame] | 74 | 	struct device *hwmon_dev; | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 75 | 	struct mutex update_lock; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 |  | 
 | 77 | 	u8 control; | 
 | 78 | 	u8 aout; | 
 | 79 | }; | 
 | 80 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | static void pcf8591_init_client(struct i2c_client *client); | 
 | 82 | static int pcf8591_read_channel(struct device *dev, int channel); | 
 | 83 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | /* following are the sysfs callback functions */ | 
 | 85 | #define show_in_channel(channel)					\ | 
| Yani Ioannou | a5099cf | 2005-05-17 06:42:25 -0400 | [diff] [blame] | 86 | static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf)	\ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | {									\ | 
 | 88 | 	return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ | 
 | 89 | }									\ | 
 | 90 | static DEVICE_ATTR(in##channel##_input, S_IRUGO,			\ | 
 | 91 | 		   show_in##channel##_input, NULL); | 
 | 92 |  | 
 | 93 | show_in_channel(0); | 
 | 94 | show_in_channel(1); | 
 | 95 | show_in_channel(2); | 
 | 96 | show_in_channel(3); | 
 | 97 |  | 
| Yani Ioannou | a5099cf | 2005-05-17 06:42:25 -0400 | [diff] [blame] | 98 | static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 99 | { | 
 | 100 | 	struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); | 
 | 101 | 	return sprintf(buf, "%d\n", data->aout * 10); | 
 | 102 | } | 
 | 103 |  | 
| Yani Ioannou | a5099cf | 2005-05-17 06:42:25 -0400 | [diff] [blame] | 104 | static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | { | 
 | 106 | 	unsigned int value; | 
 | 107 | 	struct i2c_client *client = to_i2c_client(dev); | 
 | 108 | 	struct pcf8591_data *data = i2c_get_clientdata(client); | 
 | 109 | 	if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) { | 
 | 110 | 		data->aout = value; | 
 | 111 | 		i2c_smbus_write_byte_data(client, data->control, data->aout); | 
 | 112 | 		return count; | 
 | 113 | 	} | 
 | 114 | 	return -EINVAL; | 
 | 115 | } | 
 | 116 |  | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 117 | static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | 		   show_out0_ouput, set_out0_output); | 
 | 119 |  | 
| Yani Ioannou | a5099cf | 2005-05-17 06:42:25 -0400 | [diff] [blame] | 120 | static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | { | 
 | 122 | 	struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); | 
 | 123 | 	return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); | 
 | 124 | } | 
 | 125 |  | 
| Yani Ioannou | a5099cf | 2005-05-17 06:42:25 -0400 | [diff] [blame] | 126 | static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | { | 
 | 128 | 	struct i2c_client *client = to_i2c_client(dev); | 
 | 129 | 	struct pcf8591_data *data = i2c_get_clientdata(client); | 
 | 130 | 	unsigned long val = simple_strtoul(buf, NULL, 10); | 
 | 131 |  | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 132 | 	mutex_lock(&data->update_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | 	if (val) | 
 | 134 | 		data->control |= PCF8591_CONTROL_AOEF; | 
 | 135 | 	else | 
 | 136 | 		data->control &= ~PCF8591_CONTROL_AOEF; | 
 | 137 | 	i2c_smbus_write_byte(client, data->control); | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 138 | 	mutex_unlock(&data->update_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 139 | 	return count; | 
 | 140 | } | 
 | 141 |  | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 142 | static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | 		   show_out0_enable, set_out0_enable); | 
 | 144 |  | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 145 | static struct attribute *pcf8591_attributes[] = { | 
 | 146 | 	&dev_attr_out0_enable.attr, | 
 | 147 | 	&dev_attr_out0_output.attr, | 
 | 148 | 	&dev_attr_in0_input.attr, | 
 | 149 | 	&dev_attr_in1_input.attr, | 
 | 150 | 	NULL | 
 | 151 | }; | 
 | 152 |  | 
 | 153 | static const struct attribute_group pcf8591_attr_group = { | 
 | 154 | 	.attrs = pcf8591_attributes, | 
 | 155 | }; | 
 | 156 |  | 
 | 157 | static struct attribute *pcf8591_attributes_opt[] = { | 
 | 158 | 	&dev_attr_in2_input.attr, | 
 | 159 | 	&dev_attr_in3_input.attr, | 
 | 160 | 	NULL | 
 | 161 | }; | 
 | 162 |  | 
 | 163 | static const struct attribute_group pcf8591_attr_group_opt = { | 
 | 164 | 	.attrs = pcf8591_attributes_opt, | 
 | 165 | }; | 
 | 166 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | /* | 
 | 168 |  * Real code | 
 | 169 |  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 170 |  | 
| Jean Delvare | 8b77e6a | 2008-07-16 19:30:06 +0200 | [diff] [blame] | 171 | static int pcf8591_probe(struct i2c_client *client, | 
 | 172 | 			 const struct i2c_device_id *id) | 
 | 173 | { | 
 | 174 | 	struct pcf8591_data *data; | 
 | 175 | 	int err; | 
 | 176 |  | 
| Deepak Saxena | 5263ebb | 2005-10-17 23:09:43 +0200 | [diff] [blame] | 177 | 	if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | 		err = -ENOMEM; | 
 | 179 | 		goto exit; | 
 | 180 | 	} | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 181 |  | 
| Jean Delvare | f741f67 | 2008-07-14 22:38:36 +0200 | [diff] [blame] | 182 | 	i2c_set_clientdata(client, data); | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 183 | 	mutex_init(&data->update_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 185 | 	/* Initialize the PCF8591 chip */ | 
| Jean Delvare | f741f67 | 2008-07-14 22:38:36 +0200 | [diff] [blame] | 186 | 	pcf8591_init_client(client); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 187 |  | 
 | 188 | 	/* Register sysfs hooks */ | 
| Jean Delvare | f741f67 | 2008-07-14 22:38:36 +0200 | [diff] [blame] | 189 | 	err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group); | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 190 | 	if (err) | 
| Jean Delvare | 8b77e6a | 2008-07-16 19:30:06 +0200 | [diff] [blame] | 191 | 		goto exit_kfree; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 |  | 
 | 193 | 	/* Register input2 if not in "two differential inputs" mode */ | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 194 | 	if (input_mode != 3) { | 
| Jean Delvare | f741f67 | 2008-07-14 22:38:36 +0200 | [diff] [blame] | 195 | 		if ((err = device_create_file(&client->dev, | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 196 | 					      &dev_attr_in2_input))) | 
 | 197 | 			goto exit_sysfs_remove; | 
 | 198 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 |  | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 200 | 	/* Register input3 only in "four single ended inputs" mode */ | 
 | 201 | 	if (input_mode == 0) { | 
| Jean Delvare | f741f67 | 2008-07-14 22:38:36 +0200 | [diff] [blame] | 202 | 		if ((err = device_create_file(&client->dev, | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 203 | 					      &dev_attr_in3_input))) | 
 | 204 | 			goto exit_sysfs_remove; | 
 | 205 | 	} | 
 | 206 |  | 
| Jean Delvare | 4275fcd | 2010-10-28 20:31:49 +0200 | [diff] [blame] | 207 | 	data->hwmon_dev = hwmon_device_register(&client->dev); | 
 | 208 | 	if (IS_ERR(data->hwmon_dev)) { | 
 | 209 | 		err = PTR_ERR(data->hwmon_dev); | 
 | 210 | 		goto exit_sysfs_remove; | 
 | 211 | 	} | 
 | 212 |  | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 213 | 	return 0; | 
 | 214 |  | 
 | 215 | exit_sysfs_remove: | 
| Jean Delvare | f741f67 | 2008-07-14 22:38:36 +0200 | [diff] [blame] | 216 | 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); | 
 | 217 | 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 | exit_kfree: | 
 | 219 | 	kfree(data); | 
 | 220 | exit: | 
 | 221 | 	return err; | 
 | 222 | } | 
 | 223 |  | 
| Jean Delvare | 8b77e6a | 2008-07-16 19:30:06 +0200 | [diff] [blame] | 224 | static int pcf8591_remove(struct i2c_client *client) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 225 | { | 
| Jean Delvare | 4275fcd | 2010-10-28 20:31:49 +0200 | [diff] [blame] | 226 | 	struct pcf8591_data *data = i2c_get_clientdata(client); | 
 | 227 |  | 
 | 228 | 	hwmon_device_unregister(data->hwmon_dev); | 
| Jean Delvare | 7d9db67 | 2006-09-03 22:20:24 +0200 | [diff] [blame] | 229 | 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); | 
 | 230 | 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 231 | 	kfree(i2c_get_clientdata(client)); | 
 | 232 | 	return 0; | 
 | 233 | } | 
 | 234 |  | 
 | 235 | /* Called when we have found a new PCF8591. */ | 
 | 236 | static void pcf8591_init_client(struct i2c_client *client) | 
 | 237 | { | 
 | 238 | 	struct pcf8591_data *data = i2c_get_clientdata(client); | 
 | 239 | 	data->control = PCF8591_INIT_CONTROL; | 
 | 240 | 	data->aout = PCF8591_INIT_AOUT; | 
 | 241 |  | 
 | 242 | 	i2c_smbus_write_byte_data(client, data->control, data->aout); | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 243 |  | 
 | 244 | 	/* The first byte transmitted contains the conversion code of the | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 245 | 	   previous read cycle. FLUSH IT! */ | 
 | 246 | 	i2c_smbus_read_byte(client); | 
 | 247 | } | 
 | 248 |  | 
 | 249 | static int pcf8591_read_channel(struct device *dev, int channel) | 
 | 250 | { | 
 | 251 | 	u8 value; | 
 | 252 | 	struct i2c_client *client = to_i2c_client(dev); | 
 | 253 | 	struct pcf8591_data *data = i2c_get_clientdata(client); | 
 | 254 |  | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 255 | 	mutex_lock(&data->update_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 256 |  | 
 | 257 | 	if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) { | 
 | 258 | 		data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) | 
 | 259 | 			      | channel; | 
 | 260 | 		i2c_smbus_write_byte(client, data->control); | 
| Jean Delvare | fb4504f | 2009-03-30 21:46:43 +0200 | [diff] [blame] | 261 |  | 
 | 262 | 		/* The first byte transmitted contains the conversion code of | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 263 | 		   the previous read cycle. FLUSH IT! */ | 
 | 264 | 		i2c_smbus_read_byte(client); | 
 | 265 | 	} | 
 | 266 | 	value = i2c_smbus_read_byte(client); | 
 | 267 |  | 
| Ingo Molnar | 5c085d3 | 2006-01-18 23:16:04 +0100 | [diff] [blame] | 268 | 	mutex_unlock(&data->update_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 269 |  | 
 | 270 | 	if ((channel == 2 && input_mode == 2) || | 
 | 271 | 	    (channel != 3 && (input_mode == 1 || input_mode == 3))) | 
 | 272 | 		return (10 * REG_TO_SIGNED(value)); | 
 | 273 | 	else | 
 | 274 | 		return (10 * value); | 
 | 275 | } | 
 | 276 |  | 
| Jean Delvare | 8b77e6a | 2008-07-16 19:30:06 +0200 | [diff] [blame] | 277 | static const struct i2c_device_id pcf8591_id[] = { | 
 | 278 | 	{ "pcf8591", 0 }, | 
 | 279 | 	{ } | 
 | 280 | }; | 
 | 281 | MODULE_DEVICE_TABLE(i2c, pcf8591_id); | 
 | 282 |  | 
 | 283 | static struct i2c_driver pcf8591_driver = { | 
 | 284 | 	.driver = { | 
 | 285 | 		.name	= "pcf8591", | 
 | 286 | 	}, | 
 | 287 | 	.probe		= pcf8591_probe, | 
 | 288 | 	.remove		= pcf8591_remove, | 
 | 289 | 	.id_table	= pcf8591_id, | 
| Jean Delvare | 8b77e6a | 2008-07-16 19:30:06 +0200 | [diff] [blame] | 290 | }; | 
 | 291 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 292 | static int __init pcf8591_init(void) | 
 | 293 | { | 
 | 294 | 	if (input_mode < 0 || input_mode > 3) { | 
| Joe Perches | 2caec13 | 2010-10-20 06:51:45 +0000 | [diff] [blame] | 295 | 		pr_warn("invalid input_mode (%d)\n", input_mode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | 		input_mode = 0; | 
 | 297 | 	} | 
 | 298 | 	return i2c_add_driver(&pcf8591_driver); | 
 | 299 | } | 
 | 300 |  | 
 | 301 | static void __exit pcf8591_exit(void) | 
 | 302 | { | 
 | 303 | 	i2c_del_driver(&pcf8591_driver); | 
 | 304 | } | 
 | 305 |  | 
 | 306 | MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>"); | 
 | 307 | MODULE_DESCRIPTION("PCF8591 driver"); | 
 | 308 | MODULE_LICENSE("GPL"); | 
 | 309 |  | 
 | 310 | module_init(pcf8591_init); | 
 | 311 | module_exit(pcf8591_exit); |