1 /*
2  * Copyright (C) 2001,2002,2003 Broadcom Corporation
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 
19 /*
20  * SMBus/I2C device driver for the MAX1617 temperature sensor
21  */
22 
23 #include <linux/config.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/timer.h>
28 #include <linux/errno.h>
29 
30 #include <linux/i2c.h>
31 #include <linux/i2c-algo-sibyte.h>
32 
33 #define IF_NAME "max1617"
34 
35 #define MAX1617_SMBUS_DEV	0x2A
36 #define MAX1617_LOCAL           0
37 #define MAX1617_REMOTE          1
38 #define MAX1617_STATUS          2
39 #define MAX1617_POLL_PERIOD    10
40 
41 static int max1617_verbose = 0;
42 static int max1617_polling = 1;
43 
44 /* Addresses to scan */
45 static unsigned short normal_i2c[] = {MAX1617_SMBUS_DEV, I2C_CLIENT_END};
46 static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
47 static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
48 static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
49 static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
50 static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
51 static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
52 
53 static struct i2c_client_address_data addr_data = {
54         normal_i2c, normal_i2c_range,
55         probe, probe_range,
56         ignore, ignore_range,
57         force
58 };
59 
60 struct max1617_info {
61         struct i2c_client *client;
62         struct timer_list  timer;
63         int                local;
64         int                remote;
65 };
66 
67 static int max1617_probe(struct i2c_adapter *adap);
68 static int max1617_detach(struct i2c_client *device);
69 static int max1617_command(struct i2c_client *device, unsigned int cmd, void *arg);
70 static void max1617_inc_use(struct i2c_client *device);
71 static void max1617_dec_use(struct i2c_client *device);
72 
73 struct i2c_driver i2c_driver_max1617 = {
74 	name:           IF_NAME,
75 	id:             I2C_DRIVERID_MAX1617,
76 	flags:          I2C_DF_NOTIFY,
77 	attach_adapter: max1617_probe,
78 	detach_client:  max1617_detach,
79 	command:        max1617_command,
80 	inc_use:        max1617_inc_use,
81 	dec_use:        max1617_dec_use
82 };
83 \
max1617_read(struct i2c_client * client,unsigned char subaddr)84 static int max1617_read(struct i2c_client *client, unsigned char subaddr)
85 {
86         return i2c_smbus_read_byte_data(client, subaddr);
87 }
88 
89 /* poll the device, check for temperature/status changes */
max1617_update(unsigned long arg)90 static void max1617_update(unsigned long arg)
91 {
92         struct max1617_info *m = (struct max1617_info *)arg;
93         int status, remote, local;
94         char statstr[50];
95 
96         status = max1617_read(m->client, MAX1617_STATUS);
97         remote = max1617_read(m->client, MAX1617_REMOTE);
98         local  = max1617_read(m->client, MAX1617_LOCAL);
99         if (status < 0 || remote < 0 || local < 0) {
100                 printk(KERN_ERR IF_NAME ": sensor device did not respond.\n");
101         } else {
102                 statstr[0] = 0;
103                 if (status & 0x80) strcat(statstr,"Busy ");
104                 if (status & 0x40) strcat(statstr,"HiTempLcl ");
105                 if (status & 0x20) strcat(statstr,"LoTempLcl ");
106                 if (status & 0x10) strcat(statstr,"HiTempRem ");
107                 if (status & 0x08) strcat(statstr,"LoTempRem ");
108                 if (status & 0x04) strcat(statstr,"Fault ");
109 
110                 if (max1617_verbose || (local != m->local) || (remote != m->remote)) {
111                         printk(KERN_DEBUG IF_NAME ": Temperature - CPU: %dC  Board: %dC  Status:%02X [ %s]\n",
112                                remote, local, status, statstr);
113                 }
114                 m->local = local;
115                 m->remote = remote;
116                 mod_timer(&m->timer, jiffies + (HZ * MAX1617_POLL_PERIOD));
117         }
118 }
119 
120 /* attach to an instance of the device that was probed on a bus */
max1617_attach(struct i2c_adapter * adap,int addr,unsigned short flags,int kind)121 static int max1617_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind)
122 {
123         struct max1617_info *m;
124         struct i2c_client   *client;
125         int err;
126 
127         client = kmalloc(sizeof(*client), GFP_KERNEL);
128         if (client == NULL)
129                 return -ENOMEM;
130         client->adapter = adap;
131         client->addr = addr;
132 	client->driver = &i2c_driver_max1617;
133         sprintf(client->name, "%s-%x", IF_NAME, addr);
134         if ((err = i2c_attach_client(client)) < 0) {
135                 kfree(client);
136                 return err;
137         }
138 
139         m = kmalloc(sizeof(*m), GFP_KERNEL);
140         if (m == NULL) {
141                 i2c_detach_client(client);
142                 kfree(client);
143                 return -ENOMEM;
144         }
145         m->client = client;
146         m->remote = m->local = 0;
147         init_timer(&m->timer);
148         m->timer.data = (unsigned long)m;
149         m->timer.function = max1617_update;
150         if (max1617_polling) {
151                 m->timer.expires = jiffies + (HZ * MAX1617_POLL_PERIOD);
152                 add_timer(&m->timer);
153         }
154         client->data = m;
155         return 0;
156 }
157 
158 /* initiate probing on a particular bus */
max1617_probe(struct i2c_adapter * adap)159 static int max1617_probe(struct i2c_adapter *adap)
160 {
161         /* Look for this device on the given adapter (bus) */
162         if (adap->id == (I2C_ALGO_SIBYTE | I2C_HW_SIBYTE))
163                 return i2c_probe(adap, &addr_data, &max1617_attach);
164         else
165                 return 0;
166 }
167 
max1617_detach(struct i2c_client * device)168 static int max1617_detach(struct i2c_client *device)
169 {
170         struct max1617_info *m = (struct max1617_info *)device->data;
171 	int rc = 0;
172 
173 	if ((rc = i2c_detach_client(device)) != 0) {
174 		printk(IF_NAME "detach failed: %d\n", rc);
175 	} else {
176 		kfree(device);
177 		if (max1617_polling)
178 			del_timer(&m->timer);
179 		kfree(m);
180 	}
181 	return rc;
182 }
183 
max1617_command(struct i2c_client * device,unsigned int cmd,void * arg)184 static int max1617_command(struct i2c_client *device, unsigned int cmd, void *arg)
185 {
186         return 0;
187 }
188 
max1617_inc_use(struct i2c_client * client)189 static void max1617_inc_use(struct i2c_client *client)
190 {
191 #ifdef MODULE
192 	MOD_INC_USE_COUNT;
193 #endif
194 }
195 
max1617_dec_use(struct i2c_client * client)196 static void max1617_dec_use(struct i2c_client *client)
197 {
198 #ifdef MODULE
199 	MOD_DEC_USE_COUNT;
200 #endif
201 }
202 
i2c_max1617_init(void)203 void i2c_max1617_init(void)
204 {
205         i2c_add_driver(&i2c_driver_max1617);
206 }
207 
208 EXPORT_NO_SYMBOLS;
209 
210 #ifdef MODULE
211 MODULE_AUTHOR("Kip Walker, Broadcom Corp.");
212 MODULE_DESCRIPTION("Max 1617 temperature sensor for SiByte SOC boards");
213 MODULE_LICENSE("GPL");
214 
init_module(void)215 int init_module(void)
216 {
217 	i2c_max1617_init();
218 	return 0;
219 }
220 
cleanup_module(void)221 void cleanup_module(void)
222 {
223         i2c_del_driver(&i2c_driver_max1617);
224 }
225 #endif
226