1 /* $Id: envctrl.c,v 1.7 1998/06/10 07:25:28 davem Exp $
2 * envctrl.c: Temperature and Fan monitoring on Machines providing it.
4 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
7 #include <linux/config.h>
8 #include <linux/module.h>
9 #include <linux/sched.h>
10 #include <linux/errno.h>
11 #include <linux/delay.h>
12 #include <linux/ioport.h>
13 #include <linux/init.h>
14 #include <linux/miscdevice.h>
17 #include <asm/uaccess.h>
18 #include <asm/envctrl.h>
20 #define ENVCTRL_MINOR 162
26 #define PCF8584_ADDRESS 0x55
28 #define CONTROL_PIN 0x80
29 #define CONTROL_ES0 0x40
30 #define CONTROL_ES1 0x20
31 #define CONTROL_ES2 0x10
32 #define CONTROL_ENI 0x08
33 #define CONTROL_STA 0x04
34 #define CONTROL_STO 0x02
35 #define CONTROL_ACK 0x01
37 #define STATUS_PIN 0x80
38 #define STATUS_STS 0x20
39 #define STATUS_BER 0x10
40 #define STATUS_LRB 0x08
41 #define STATUS_AD0 0x08
42 #define STATUS_AAB 0x04
43 #define STATUS_LAB 0x02
44 #define STATUS_BB 0x01
49 #define BUS_CLK_90 0x00
50 #define BUS_CLK_45 0x01
51 #define BUS_CLK_11 0x02
52 #define BUS_CLK_1_5 0x03
61 #define I2C_WRITE 0x00
66 __volatile__
unsigned char data
;
67 __volatile__
unsigned char csr
;
70 static struct pcf8584_reg
*i2c
;
80 static struct i2c_addr_map devmap
[] = {
81 { 0x38, 0x78, "PCF8574A" },
82 { 0x20, 0x78, "TDA8444" },
83 { 0x48, 0x78, "PCF8591" },
85 #define NR_DEVMAP (sizeof(devmap) / sizeof(devmap[0]))
89 PUT_DATA(__volatile__
unsigned char *data
, char *buffer
, int user
)
92 if (put_user(*data
, buffer
))
100 static __inline__
int
101 GET_DATA(__volatile__
unsigned char *data
, const char *buffer
, int user
)
104 if (get_user(*data
, buffer
))
113 i2c_read(unsigned char dev
, char *buffer
, int len
, int user
)
123 i2c
->data
= (dev
<< 1) | I2C_READ
;
125 while (!(i2c
->csr
& STATUS_BB
))
128 i2c
->csr
= CONTROL_PIN
| CONTROL_ES0
| CONTROL_STA
| CONTROL_ACK
;
132 while ((stat
= i2c
->csr
) & STATUS_PIN
)
135 if (stat
& STATUS_LRB
)
138 if (count
== (len
- 2))
142 error
= PUT_DATA(&i2c
->data
, buffer
++, user
);
150 i2c
->csr
= CONTROL_ES0
;
151 if (!error
&& (++count
> 0))
152 error
= PUT_DATA(&i2c
->data
, buffer
++, user
);
157 while ((stat
= i2c
->csr
) & STATUS_PIN
)
161 i2c
->csr
= CONTROL_PIN
| CONTROL_ES0
| CONTROL_STO
| CONTROL_ACK
;
162 if (!error
&& (++count
> 0))
163 error
= PUT_DATA(&i2c
->data
, buffer
++, user
);
173 i2c_write(unsigned char dev
, const char *buffer
, int len
, int user
)
178 while (!(i2c
->csr
& STATUS_BB
))
181 i2c
->data
= (dev
<< 1) | I2C_WRITE
;
182 i2c
->csr
= CONTROL_PIN
| CONTROL_ES0
| CONTROL_STA
| CONTROL_ACK
;
188 while ((stat
= i2c
->csr
) & STATUS_PIN
)
191 if (stat
& STATUS_LRB
)
197 error
= GET_DATA(&i2c
->data
, buffer
++, user
);
205 i2c
->csr
= CONTROL_PIN
| CONTROL_ES0
| CONTROL_STO
| CONTROL_ACK
;
209 __initfunc(static int i2c_scan_bus(void))
214 for (dev
= 1; dev
< 128; dev
++) {
215 if (i2c_write(dev
, 0, 0, 0) == 0) {
216 #ifdef DEBUG_BUS_SCAN
218 for (i
= 0; i
< NR_DEVMAP
; i
++)
219 if ((dev
& devmap
[i
].mask
) == devmap
[i
].addr
)
221 printk("envctrl: i2c device at %02x: %s\n", dev
,
222 i
< NR_DEVMAP
? devmap
[i
].name
: "unknown");
227 return count
? 0 : -ENODEV
;
231 envctrl_llseek(struct file
*file
, loff_t offset
, int type
)
237 envctrl_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
239 unsigned long addr
= (unsigned long)file
->private_data
;
241 return i2c_read(addr
, buf
, count
, 1);
245 envctrl_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
247 unsigned long addr
= (unsigned long)file
->private_data
;
249 return i2c_write(addr
, buf
, count
, 1);
253 envctrl_ioctl(struct inode
*inode
, struct file
*file
,
254 unsigned int cmd
, unsigned long arg
)
261 if (get_user(addr
, (int *)arg
))
264 file
->private_data
= (void *)data
;
267 addr
= (unsigned long)file
->private_data
;
268 if (put_user(addr
, (int *)arg
))
278 envctrl_open(struct inode
*inode
, struct file
*file
)
280 file
->private_data
= 0;
286 envctrl_release(struct inode
*inode
, struct file
*file
)
292 static struct file_operations envctrl_fops
= {
305 static struct miscdevice envctrl_dev
= {
312 int init_module(void)
314 __initfunc(int envctrl_init(void))
318 struct linux_ebus
*ebus
;
319 struct linux_ebus_device
*edev
= 0;
321 for_each_ebus(ebus
) {
322 for_each_ebusdev(edev
, ebus
) {
323 if (!strcmp(edev
->prom_name
, "SUNW,envctrl"))
325 if (!strcmp(edev
->prom_name
, "SUNW,rasctrl"))
333 if (check_region(edev
->base_address
[0], sizeof(*i2c
))) {
334 printk("%s: Can't get region %lx, %d\n",
335 __FUNCTION__
, edev
->base_address
[0], (int)sizeof(*i2c
));
339 i2c
= (struct pcf8584_reg
*)edev
->base_address
[0];
341 request_region((unsigned long)i2c
, sizeof(*i2c
), "i2c");
343 i2c
->csr
= CONTROL_PIN
;
344 i2c
->data
= PCF8584_ADDRESS
;
345 i2c
->csr
= CONTROL_PIN
| CONTROL_ES1
;
346 i2c
->data
= CLK_4_43
| BUS_CLK_90
;
347 i2c
->csr
= CONTROL_PIN
| CONTROL_ES0
| CONTROL_ACK
;
350 if (misc_register(&envctrl_dev
)) {
351 printk("%s: unable to get misc minor %d\n",
352 __FUNCTION__
, envctrl_dev
.minor
);
353 release_region((unsigned long)i2c
, sizeof(*i2c
));
356 return i2c_scan_bus();
364 void cleanup_module(void)
366 misc_deregister(&envctrl_dev
);
367 release_region((unsigned long)i2c
, sizeof(*i2c
));