xref: /openbmc/linux/drivers/hwmon/atxp1.c (revision 8dea1b4e7726faf19b66d70f9f3737e85ef04a36)
18d5d45fbSJean Delvare /*
2f24d548bSGuenter Roeck  * atxp1.c - kernel module for setting CPU VID and general purpose
3f24d548bSGuenter Roeck  *	     I/Os using the Attansic ATXP1 chip.
4f24d548bSGuenter Roeck  *
5f24d548bSGuenter Roeck  * This program is free software; you can redistribute it and/or modify
6f24d548bSGuenter Roeck  * it under the terms of the GNU General Public License as published by
7f24d548bSGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
8f24d548bSGuenter Roeck  * (at your option) any later version.
9f24d548bSGuenter Roeck  *
10f24d548bSGuenter Roeck  * This program is distributed in the hope that it will be useful,
11f24d548bSGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12f24d548bSGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13f24d548bSGuenter Roeck  * GNU General Public License for more details.
14f24d548bSGuenter Roeck  *
15f24d548bSGuenter Roeck  * You should have received a copy of the GNU General Public License
16f24d548bSGuenter Roeck  * along with this program; if not, write to the Free Software
17f24d548bSGuenter Roeck  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18f24d548bSGuenter Roeck  *
198d5d45fbSJean Delvare  */
208d5d45fbSJean Delvare 
218d5d45fbSJean Delvare #include <linux/kernel.h>
228d5d45fbSJean Delvare #include <linux/init.h>
238d5d45fbSJean Delvare #include <linux/module.h>
240cacdf29SJean Delvare #include <linux/jiffies.h>
258d5d45fbSJean Delvare #include <linux/i2c.h>
26943b0830SMark M. Hoffman #include <linux/hwmon.h>
27303760b4SJean Delvare #include <linux/hwmon-vid.h>
28943b0830SMark M. Hoffman #include <linux/err.h>
299a61bf63SIngo Molnar #include <linux/mutex.h>
30a5ebe668SJean Delvare #include <linux/sysfs.h>
315a0e3ad6STejun Heo #include <linux/slab.h>
328d5d45fbSJean Delvare 
338d5d45fbSJean Delvare MODULE_LICENSE("GPL");
348d5d45fbSJean Delvare MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
3513b3c3faSJean Delvare MODULE_VERSION("0.6.3");
368d5d45fbSJean Delvare MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
378d5d45fbSJean Delvare 
388d5d45fbSJean Delvare #define ATXP1_VID	0x00
398d5d45fbSJean Delvare #define ATXP1_CVID	0x01
408d5d45fbSJean Delvare #define ATXP1_GPIO1	0x06
418d5d45fbSJean Delvare #define ATXP1_GPIO2	0x0a
428d5d45fbSJean Delvare #define ATXP1_VIDENA	0x20
438d5d45fbSJean Delvare #define ATXP1_VIDMASK	0x1f
448d5d45fbSJean Delvare #define ATXP1_GPIO1MASK	0x0f
458d5d45fbSJean Delvare 
4625e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
478d5d45fbSJean Delvare 
488d5d45fbSJean Delvare struct atxp1_data {
491beeffe4STony Jones 	struct device *hwmon_dev;
509a61bf63SIngo Molnar 	struct mutex update_lock;
518d5d45fbSJean Delvare 	unsigned long last_updated;
528d5d45fbSJean Delvare 	u8 valid;
538d5d45fbSJean Delvare 	struct {
548d5d45fbSJean Delvare 		u8 vid;		/* VID output register */
558d5d45fbSJean Delvare 		u8 cpu_vid; /* VID input from CPU */
568d5d45fbSJean Delvare 		u8 gpio1;   /* General purpose I/O register 1 */
578d5d45fbSJean Delvare 		u8 gpio2;   /* General purpose I/O register 2 */
588d5d45fbSJean Delvare 	} reg;
598d5d45fbSJean Delvare 	u8 vrm;			/* Detected CPU VRM */
608d5d45fbSJean Delvare };
618d5d45fbSJean Delvare 
628d5d45fbSJean Delvare static struct atxp1_data *atxp1_update_device(struct device *dev)
638d5d45fbSJean Delvare {
648d5d45fbSJean Delvare 	struct i2c_client *client;
658d5d45fbSJean Delvare 	struct atxp1_data *data;
668d5d45fbSJean Delvare 
678d5d45fbSJean Delvare 	client = to_i2c_client(dev);
688d5d45fbSJean Delvare 	data = i2c_get_clientdata(client);
698d5d45fbSJean Delvare 
709a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
718d5d45fbSJean Delvare 
720cacdf29SJean Delvare 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
738d5d45fbSJean Delvare 
748d5d45fbSJean Delvare 		/* Update local register data */
758d5d45fbSJean Delvare 		data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
76f24d548bSGuenter Roeck 		data->reg.cpu_vid = i2c_smbus_read_byte_data(client,
77f24d548bSGuenter Roeck 							     ATXP1_CVID);
788d5d45fbSJean Delvare 		data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
798d5d45fbSJean Delvare 		data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
808d5d45fbSJean Delvare 
818d5d45fbSJean Delvare 		data->valid = 1;
828d5d45fbSJean Delvare 	}
838d5d45fbSJean Delvare 
849a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
858d5d45fbSJean Delvare 
867fe83ad8SFrans Meulenbroeks 	return data;
878d5d45fbSJean Delvare }
888d5d45fbSJean Delvare 
898d5d45fbSJean Delvare /* sys file functions for cpu0_vid */
90f24d548bSGuenter Roeck static ssize_t atxp1_showvcore(struct device *dev,
91f24d548bSGuenter Roeck 			       struct device_attribute *attr, char *buf)
928d5d45fbSJean Delvare {
938d5d45fbSJean Delvare 	int size;
948d5d45fbSJean Delvare 	struct atxp1_data *data;
958d5d45fbSJean Delvare 
968d5d45fbSJean Delvare 	data = atxp1_update_device(dev);
978d5d45fbSJean Delvare 
98f24d548bSGuenter Roeck 	size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK,
99f24d548bSGuenter Roeck 						 data->vrm));
1008d5d45fbSJean Delvare 
1018d5d45fbSJean Delvare 	return size;
1028d5d45fbSJean Delvare }
1038d5d45fbSJean Delvare 
104f24d548bSGuenter Roeck static ssize_t atxp1_storevcore(struct device *dev,
105f24d548bSGuenter Roeck 				struct device_attribute *attr,
106f24d548bSGuenter Roeck 				const char *buf, size_t count)
1078d5d45fbSJean Delvare {
1088d5d45fbSJean Delvare 	struct atxp1_data *data;
1098d5d45fbSJean Delvare 	struct i2c_client *client;
110c41bdb52SAlexey Dobriyan 	int vid, cvid;
111f24d548bSGuenter Roeck 	unsigned long vcore;
112f24d548bSGuenter Roeck 	int err;
1138d5d45fbSJean Delvare 
1148d5d45fbSJean Delvare 	client = to_i2c_client(dev);
1158d5d45fbSJean Delvare 	data = atxp1_update_device(dev);
1168d5d45fbSJean Delvare 
117f24d548bSGuenter Roeck 	err = kstrtoul(buf, 10, &vcore);
118f24d548bSGuenter Roeck 	if (err)
119f24d548bSGuenter Roeck 		return err;
120f24d548bSGuenter Roeck 
1218d5d45fbSJean Delvare 	vcore /= 25;
1228d5d45fbSJean Delvare 	vcore *= 25;
1238d5d45fbSJean Delvare 
1248d5d45fbSJean Delvare 	/* Calculate VID */
1258d5d45fbSJean Delvare 	vid = vid_to_reg(vcore, data->vrm);
1268d5d45fbSJean Delvare 	if (vid < 0) {
1278d5d45fbSJean Delvare 		dev_err(dev, "VID calculation failed.\n");
128674d0ed8SGuenter Roeck 		return vid;
1298d5d45fbSJean Delvare 	}
1308d5d45fbSJean Delvare 
131f24d548bSGuenter Roeck 	/*
132f24d548bSGuenter Roeck 	 * If output enabled, use control register value.
133f24d548bSGuenter Roeck 	 * Otherwise original CPU VID
134f24d548bSGuenter Roeck 	 */
1358d5d45fbSJean Delvare 	if (data->reg.vid & ATXP1_VIDENA)
1368d5d45fbSJean Delvare 		cvid = data->reg.vid & ATXP1_VIDMASK;
1378d5d45fbSJean Delvare 	else
1388d5d45fbSJean Delvare 		cvid = data->reg.cpu_vid;
1398d5d45fbSJean Delvare 
1408d5d45fbSJean Delvare 	/* Nothing changed, aborting */
1418d5d45fbSJean Delvare 	if (vid == cvid)
1428d5d45fbSJean Delvare 		return count;
1438d5d45fbSJean Delvare 
144f24d548bSGuenter Roeck 	dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid);
1458d5d45fbSJean Delvare 
1468d5d45fbSJean Delvare 	/* Write every 25 mV step to increase stability */
1478d5d45fbSJean Delvare 	if (cvid > vid) {
148f24d548bSGuenter Roeck 		for (; cvid >= vid; cvid--)
149f24d548bSGuenter Roeck 			i2c_smbus_write_byte_data(client,
150f24d548bSGuenter Roeck 						ATXP1_VID, cvid | ATXP1_VIDENA);
151f24d548bSGuenter Roeck 	} else {
152f24d548bSGuenter Roeck 		for (; cvid <= vid; cvid++)
153f24d548bSGuenter Roeck 			i2c_smbus_write_byte_data(client,
154f24d548bSGuenter Roeck 						ATXP1_VID, cvid | ATXP1_VIDENA);
1558d5d45fbSJean Delvare 	}
1568d5d45fbSJean Delvare 
1578d5d45fbSJean Delvare 	data->valid = 0;
1588d5d45fbSJean Delvare 
1598d5d45fbSJean Delvare 	return count;
1608d5d45fbSJean Delvare }
1618d5d45fbSJean Delvare 
162f24d548bSGuenter Roeck /*
163f24d548bSGuenter Roeck  * CPU core reference voltage
164f24d548bSGuenter Roeck  * unit: millivolt
1658d5d45fbSJean Delvare  */
166f24d548bSGuenter Roeck static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore,
167f24d548bSGuenter Roeck 		   atxp1_storevcore);
1688d5d45fbSJean Delvare 
1698d5d45fbSJean Delvare /* sys file functions for GPIO1 */
170f24d548bSGuenter Roeck static ssize_t atxp1_showgpio1(struct device *dev,
171f24d548bSGuenter Roeck 			       struct device_attribute *attr, char *buf)
1728d5d45fbSJean Delvare {
1738d5d45fbSJean Delvare 	int size;
1748d5d45fbSJean Delvare 	struct atxp1_data *data;
1758d5d45fbSJean Delvare 
1768d5d45fbSJean Delvare 	data = atxp1_update_device(dev);
1778d5d45fbSJean Delvare 
1788d5d45fbSJean Delvare 	size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
1798d5d45fbSJean Delvare 
1808d5d45fbSJean Delvare 	return size;
1818d5d45fbSJean Delvare }
1828d5d45fbSJean Delvare 
183f24d548bSGuenter Roeck static ssize_t atxp1_storegpio1(struct device *dev,
184f24d548bSGuenter Roeck 				struct device_attribute *attr, const char *buf,
185f24d548bSGuenter Roeck 				size_t count)
1868d5d45fbSJean Delvare {
1878d5d45fbSJean Delvare 	struct atxp1_data *data;
1888d5d45fbSJean Delvare 	struct i2c_client *client;
189f24d548bSGuenter Roeck 	unsigned long value;
190f24d548bSGuenter Roeck 	int err;
1918d5d45fbSJean Delvare 
1928d5d45fbSJean Delvare 	client = to_i2c_client(dev);
1938d5d45fbSJean Delvare 	data = atxp1_update_device(dev);
1948d5d45fbSJean Delvare 
195f24d548bSGuenter Roeck 	err = kstrtoul(buf, 16, &value);
196f24d548bSGuenter Roeck 	if (err)
197f24d548bSGuenter Roeck 		return err;
1988d5d45fbSJean Delvare 
1998d5d45fbSJean Delvare 	value &= ATXP1_GPIO1MASK;
2008d5d45fbSJean Delvare 
2018d5d45fbSJean Delvare 	if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
202f24d548bSGuenter Roeck 		dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
2038d5d45fbSJean Delvare 
2048d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
2058d5d45fbSJean Delvare 
2068d5d45fbSJean Delvare 		data->valid = 0;
2078d5d45fbSJean Delvare 	}
2088d5d45fbSJean Delvare 
2098d5d45fbSJean Delvare 	return count;
2108d5d45fbSJean Delvare }
2118d5d45fbSJean Delvare 
212f24d548bSGuenter Roeck /*
213f24d548bSGuenter Roeck  * GPIO1 data register
214f24d548bSGuenter Roeck  * unit: Four bit as hex (e.g. 0x0f)
2158d5d45fbSJean Delvare  */
2168d5d45fbSJean Delvare static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
2178d5d45fbSJean Delvare 
2188d5d45fbSJean Delvare /* sys file functions for GPIO2 */
219f24d548bSGuenter Roeck static ssize_t atxp1_showgpio2(struct device *dev,
220f24d548bSGuenter Roeck 			       struct device_attribute *attr, char *buf)
2218d5d45fbSJean Delvare {
2228d5d45fbSJean Delvare 	int size;
2238d5d45fbSJean Delvare 	struct atxp1_data *data;
2248d5d45fbSJean Delvare 
2258d5d45fbSJean Delvare 	data = atxp1_update_device(dev);
2268d5d45fbSJean Delvare 
2278d5d45fbSJean Delvare 	size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
2288d5d45fbSJean Delvare 
2298d5d45fbSJean Delvare 	return size;
2308d5d45fbSJean Delvare }
2318d5d45fbSJean Delvare 
232f24d548bSGuenter Roeck static ssize_t atxp1_storegpio2(struct device *dev,
233f24d548bSGuenter Roeck 				struct device_attribute *attr,
234f24d548bSGuenter Roeck 				const char *buf, size_t count)
2358d5d45fbSJean Delvare {
236f24d548bSGuenter Roeck 	struct atxp1_data *data = atxp1_update_device(dev);
237f24d548bSGuenter Roeck 	struct i2c_client *client = to_i2c_client(dev);
238f24d548bSGuenter Roeck 	unsigned long value;
239f24d548bSGuenter Roeck 	int err;
2408d5d45fbSJean Delvare 
241f24d548bSGuenter Roeck 	err = kstrtoul(buf, 16, &value);
242f24d548bSGuenter Roeck 	if (err)
243f24d548bSGuenter Roeck 		return err;
244f24d548bSGuenter Roeck 	value &= 0xff;
2458d5d45fbSJean Delvare 
2468d5d45fbSJean Delvare 	if (value != data->reg.gpio2) {
247f24d548bSGuenter Roeck 		dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
2488d5d45fbSJean Delvare 
2498d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
2508d5d45fbSJean Delvare 
2518d5d45fbSJean Delvare 		data->valid = 0;
2528d5d45fbSJean Delvare 	}
2538d5d45fbSJean Delvare 
2548d5d45fbSJean Delvare 	return count;
2558d5d45fbSJean Delvare }
2568d5d45fbSJean Delvare 
257f24d548bSGuenter Roeck /*
258f24d548bSGuenter Roeck  * GPIO2 data register
259f24d548bSGuenter Roeck  * unit: Eight bit as hex (e.g. 0xff)
2608d5d45fbSJean Delvare  */
2618d5d45fbSJean Delvare static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
2628d5d45fbSJean Delvare 
263a5ebe668SJean Delvare static struct attribute *atxp1_attributes[] = {
264a5ebe668SJean Delvare 	&dev_attr_gpio1.attr,
265a5ebe668SJean Delvare 	&dev_attr_gpio2.attr,
266a5ebe668SJean Delvare 	&dev_attr_cpu0_vid.attr,
267a5ebe668SJean Delvare 	NULL
268a5ebe668SJean Delvare };
269a5ebe668SJean Delvare 
270a5ebe668SJean Delvare static const struct attribute_group atxp1_group = {
271a5ebe668SJean Delvare 	.attrs = atxp1_attributes,
272a5ebe668SJean Delvare };
273a5ebe668SJean Delvare 
2748d5d45fbSJean Delvare 
27571163c7cSJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */
276310ec792SJean Delvare static int atxp1_detect(struct i2c_client *new_client,
27771163c7cSJean Delvare 			struct i2c_board_info *info)
2788d5d45fbSJean Delvare {
27971163c7cSJean Delvare 	struct i2c_adapter *adapter = new_client->adapter;
2808d5d45fbSJean Delvare 
2818d5d45fbSJean Delvare 	u8 temp;
2828d5d45fbSJean Delvare 
2838d5d45fbSJean Delvare 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
28471163c7cSJean Delvare 		return -ENODEV;
2858d5d45fbSJean Delvare 
2868d5d45fbSJean Delvare 	/* Detect ATXP1, checking if vendor ID registers are all zero */
2878d5d45fbSJean Delvare 	if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
2888d5d45fbSJean Delvare 	     (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
2898d5d45fbSJean Delvare 	     (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
29013b3c3faSJean Delvare 	     (i2c_smbus_read_byte_data(new_client, 0xff) == 0)))
29113b3c3faSJean Delvare 		return -ENODEV;
2928d5d45fbSJean Delvare 
293f24d548bSGuenter Roeck 	/*
294f24d548bSGuenter Roeck 	 * No vendor ID, now checking if registers 0x10,0x11 (non-existent)
295f24d548bSGuenter Roeck 	 * showing the same as register 0x00
296f24d548bSGuenter Roeck 	 */
2978d5d45fbSJean Delvare 	temp = i2c_smbus_read_byte_data(new_client, 0x00);
2988d5d45fbSJean Delvare 
2998d5d45fbSJean Delvare 	if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
3008d5d45fbSJean Delvare 	      (i2c_smbus_read_byte_data(new_client, 0x11) == temp)))
30171163c7cSJean Delvare 		return -ENODEV;
30271163c7cSJean Delvare 
30371163c7cSJean Delvare 	/* Get VRM */
30471163c7cSJean Delvare 	temp = vid_which_vrm();
30571163c7cSJean Delvare 
30671163c7cSJean Delvare 	if ((temp != 90) && (temp != 91)) {
30771163c7cSJean Delvare 		dev_err(&adapter->dev, "atxp1: Not supporting VRM %d.%d\n",
30871163c7cSJean Delvare 				temp / 10, temp % 10);
30971163c7cSJean Delvare 		return -ENODEV;
31071163c7cSJean Delvare 	}
31171163c7cSJean Delvare 
31271163c7cSJean Delvare 	strlcpy(info->type, "atxp1", I2C_NAME_SIZE);
31371163c7cSJean Delvare 
31471163c7cSJean Delvare 	return 0;
31571163c7cSJean Delvare }
31671163c7cSJean Delvare 
31771163c7cSJean Delvare static int atxp1_probe(struct i2c_client *new_client,
31871163c7cSJean Delvare 		       const struct i2c_device_id *id)
31971163c7cSJean Delvare {
32071163c7cSJean Delvare 	struct atxp1_data *data;
32171163c7cSJean Delvare 	int err;
32271163c7cSJean Delvare 
323d466a353SGuenter Roeck 	data = devm_kzalloc(&new_client->dev, sizeof(struct atxp1_data),
324d466a353SGuenter Roeck 			    GFP_KERNEL);
325d466a353SGuenter Roeck 	if (!data)
326d466a353SGuenter Roeck 		return -ENOMEM;
3278d5d45fbSJean Delvare 
3288d5d45fbSJean Delvare 	/* Get VRM */
329303760b4SJean Delvare 	data->vrm = vid_which_vrm();
3308d5d45fbSJean Delvare 
33171163c7cSJean Delvare 	i2c_set_clientdata(new_client, data);
3329a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
3338d5d45fbSJean Delvare 
334a5ebe668SJean Delvare 	/* Register sysfs hooks */
335f24d548bSGuenter Roeck 	err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group);
336f24d548bSGuenter Roeck 	if (err)
337d466a353SGuenter Roeck 		return err;
338a5ebe668SJean Delvare 
3391beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
3401beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
3411beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
342a5ebe668SJean Delvare 		goto exit_remove_files;
343943b0830SMark M. Hoffman 	}
344943b0830SMark M. Hoffman 
3458d5d45fbSJean Delvare 	dev_info(&new_client->dev, "Using VRM: %d.%d\n",
3468d5d45fbSJean Delvare 			 data->vrm / 10, data->vrm % 10);
3478d5d45fbSJean Delvare 
3488d5d45fbSJean Delvare 	return 0;
3498d5d45fbSJean Delvare 
350a5ebe668SJean Delvare exit_remove_files:
351a5ebe668SJean Delvare 	sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
3528d5d45fbSJean Delvare 	return err;
3538d5d45fbSJean Delvare };
3548d5d45fbSJean Delvare 
35571163c7cSJean Delvare static int atxp1_remove(struct i2c_client *client)
3568d5d45fbSJean Delvare {
357943b0830SMark M. Hoffman 	struct atxp1_data *data = i2c_get_clientdata(client);
3588d5d45fbSJean Delvare 
3591beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
360a5ebe668SJean Delvare 	sysfs_remove_group(&client->dev.kobj, &atxp1_group);
361943b0830SMark M. Hoffman 
36271163c7cSJean Delvare 	return 0;
3638d5d45fbSJean Delvare };
3648d5d45fbSJean Delvare 
365*8dea1b4eSAxel Lin static const struct i2c_device_id atxp1_id[] = {
366*8dea1b4eSAxel Lin 	{ "atxp1", 0 },
367*8dea1b4eSAxel Lin 	{ }
368*8dea1b4eSAxel Lin };
369*8dea1b4eSAxel Lin MODULE_DEVICE_TABLE(i2c, atxp1_id);
370*8dea1b4eSAxel Lin 
371*8dea1b4eSAxel Lin static struct i2c_driver atxp1_driver = {
372*8dea1b4eSAxel Lin 	.class		= I2C_CLASS_HWMON,
373*8dea1b4eSAxel Lin 	.driver = {
374*8dea1b4eSAxel Lin 		.name	= "atxp1",
375*8dea1b4eSAxel Lin 	},
376*8dea1b4eSAxel Lin 	.probe		= atxp1_probe,
377*8dea1b4eSAxel Lin 	.remove		= atxp1_remove,
378*8dea1b4eSAxel Lin 	.id_table	= atxp1_id,
379*8dea1b4eSAxel Lin 	.detect		= atxp1_detect,
380*8dea1b4eSAxel Lin 	.address_list	= normal_i2c,
381*8dea1b4eSAxel Lin };
382*8dea1b4eSAxel Lin 
383f0967eeaSAxel Lin module_i2c_driver(atxp1_driver);
384