13 #include <linux/module.h>
14 #include <linux/errno.h>
15 #include <linux/kernel.h>
23 #include <asm/uaccess.h>
25 #define DEVNAME "pc8736x_gpio"
36 static unsigned pc8736x_gpio_base;
37 static u8 pc8736x_gpio_shadow[4];
39 #define SIO_BASE1 0x2E
40 #define SIO_BASE2 0x4E
43 #define SIO_SID_PC87365 0xe5
44 #define SIO_SID_PC87366 0xe9
48 #define PC8736X_GPIO_RANGE 16
49 #define PC8736X_GPIO_CT 32
51 #define SIO_UNIT_SEL 0x7
52 #define SIO_UNIT_ACT 0x30
53 #define SIO_GPIO_UNIT 0x7
54 #define SIO_VLM_UNIT 0x0D
55 #define SIO_TMS_UNIT 0x0E
58 #define SIO_BASE_HADDR 0x60
59 #define SIO_BASE_LADDR 0x61
62 #define SIO_GPIO_PIN_SELECT 0xF0
63 #define SIO_GPIO_PIN_CONFIG 0xF1
64 #define SIO_GPIO_PIN_EVENT 0xF2
66 static unsigned char superio_cmd = 0;
67 static unsigned char selected_device = 0xFF;
70 static int port_offset[] = { 0, 4, 8, 10 };
76 #define PORT_EVT_STST 3
80 static inline void superio_outb(
int addr,
int val)
83 outb_p(val, superio_cmd + 1);
86 static inline int superio_inb(
int addr)
89 return inb_p(superio_cmd + 1);
92 static int pc8736x_superio_present(
void)
110 static void device_select(
unsigned devldn)
113 selected_device = devldn;
116 static void select_pin(
unsigned iminor)
121 ((iminor << 1) & 0xF0) | (iminor & 0x7));
135 config = superio_inb(func_slct);
138 new_config = (config &
mask) | bits;
139 superio_outb(func_slct, new_config);
148 return pc8736x_gpio_configure_fn(index, mask, bits,
152 static int pc8736x_gpio_get(
unsigned minor)
158 val =
inb_p(pc8736x_gpio_base + port_offset[port] +
PORT_IN);
162 dev_dbg(&pdev->
dev,
"_gpio_get(%d from %x bit %d) == val %d\n",
163 minor, pc8736x_gpio_base + port_offset[port] +
PORT_IN, bit,
169 static void pc8736x_gpio_set(
unsigned minor,
int val)
176 curval =
inb_p(pc8736x_gpio_base + port_offset[port] +
PORT_OUT);
178 dev_dbg(&pdev->
dev,
"addr:%x cur:%x bit-pos:%d cur-bit:%x + new:%d -> bit-new:%d\n",
179 pc8736x_gpio_base + port_offset[port] +
PORT_OUT,
180 curval, bit, (curval & ~(1 << bit)), val, (val << bit));
182 val = (curval & ~(1 <<
bit)) | (val <<
bit);
184 dev_dbg(&pdev->
dev,
"gpio_set(minor:%d port:%d bit:%d)"
185 " %2x -> %2x\n", minor, port, bit, curval, val);
189 curval =
inb_p(pc8736x_gpio_base + port_offset[port] +
PORT_OUT);
190 val =
inb_p(pc8736x_gpio_base + port_offset[port] +
PORT_IN);
192 dev_dbg(&pdev->
dev,
"wrote %x, read: %x\n", curval, val);
193 pc8736x_gpio_shadow[
port] =
val;
196 static int pc8736x_gpio_current(
unsigned minor)
202 return ((pc8736x_gpio_shadow[port] >> bit) & 0x01);
205 static void pc8736x_gpio_change(
unsigned index)
207 pc8736x_gpio_set(index, !pc8736x_gpio_current(index));
212 .gpio_config = pc8736x_gpio_configure,
214 .gpio_get = pc8736x_gpio_get,
215 .gpio_set = pc8736x_gpio_set,
216 .gpio_change = pc8736x_gpio_change,
217 .gpio_current = pc8736x_gpio_current
222 unsigned m = iminor(inode);
234 .open = pc8736x_gpio_open,
240 static void __init pc8736x_init_shadow(
void)
245 for (port = 0; port < 4; ++
port)
246 pc8736x_gpio_shadow[port]
247 =
inb_p(pc8736x_gpio_base + port_offset[port]
252 static struct cdev pc8736x_gpio_cdev;
254 static int __init pc8736x_gpio_init(
void)
266 goto undo_platform_dev_alloc;
268 dev_info(&pdev->
dev,
"NatSemi pc8736x GPIO Driver Initializing\n");
270 if (!pc8736x_superio_present()) {
273 goto undo_platform_dev_add;
275 pc8736x_gpio_ops.
dev = &pdev->
dev;
284 goto undo_platform_dev_add;
289 dev_err(&pdev->
dev,
"GPIO unit not enabled\n");
290 goto undo_platform_dev_add;
301 goto undo_platform_dev_add;
303 dev_info(&pdev->
dev,
"GPIO ioport %x reserved\n", pc8736x_gpio_base);
306 devid =
MKDEV(major, 0);
314 dev_err(&pdev->
dev,
"register-chrdev failed: %d\n", rc);
315 goto undo_request_region;
319 dev_dbg(&pdev->
dev,
"got dynamic major %d\n", major);
322 pc8736x_init_shadow();
325 cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops);
332 undo_platform_dev_add:
334 undo_platform_dev_alloc:
340 static void __exit pc8736x_gpio_cleanup(
void)