Commit | Line | Data |
---|---|---|
65131cd5 RG |
1 | /* |
2 | * Silicon Labs C2 port Linux support for Eurotech Duramar 2150 | |
3 | * | |
4 | * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it> | |
5 | * Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License version 2 as published by | |
9 | * the Free Software Foundation | |
10 | */ | |
11 | ||
12 | #include <linux/errno.h> | |
13 | #include <linux/init.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/io.h> | |
ecd9d34a | 18 | #include <linux/ioport.h> |
65131cd5 RG |
19 | #include <linux/c2port.h> |
20 | ||
21 | #define DATA_PORT 0x325 | |
22 | #define DIR_PORT 0x326 | |
23 | #define C2D (1 << 0) | |
24 | #define C2CK (1 << 1) | |
25 | ||
26 | static DEFINE_MUTEX(update_lock); | |
27 | ||
28 | /* | |
29 | * C2 port operations | |
30 | */ | |
31 | ||
32 | static void duramar2150_c2port_access(struct c2port_device *dev, int status) | |
33 | { | |
34 | u8 v; | |
35 | ||
36 | mutex_lock(&update_lock); | |
37 | ||
38 | v = inb(DIR_PORT); | |
39 | ||
40 | /* 0 = input, 1 = output */ | |
41 | if (status) | |
42 | outb(v | (C2D | C2CK), DIR_PORT); | |
43 | else | |
44 | /* When access is "off" is important that both lines are set | |
25985edc | 45 | * as inputs or hi-impedance */ |
65131cd5 RG |
46 | outb(v & ~(C2D | C2CK), DIR_PORT); |
47 | ||
48 | mutex_unlock(&update_lock); | |
49 | } | |
50 | ||
51 | static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir) | |
52 | { | |
53 | u8 v; | |
54 | ||
55 | mutex_lock(&update_lock); | |
56 | ||
57 | v = inb(DIR_PORT); | |
58 | ||
59 | if (dir) | |
60 | outb(v & ~C2D, DIR_PORT); | |
61 | else | |
62 | outb(v | C2D, DIR_PORT); | |
63 | ||
64 | mutex_unlock(&update_lock); | |
65 | } | |
66 | ||
67 | static int duramar2150_c2port_c2d_get(struct c2port_device *dev) | |
68 | { | |
69 | return inb(DATA_PORT) & C2D; | |
70 | } | |
71 | ||
72 | static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status) | |
73 | { | |
74 | u8 v; | |
75 | ||
76 | mutex_lock(&update_lock); | |
77 | ||
78 | v = inb(DATA_PORT); | |
79 | ||
80 | if (status) | |
81 | outb(v | C2D, DATA_PORT); | |
82 | else | |
83 | outb(v & ~C2D, DATA_PORT); | |
84 | ||
85 | mutex_unlock(&update_lock); | |
86 | } | |
87 | ||
88 | static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status) | |
89 | { | |
90 | u8 v; | |
91 | ||
92 | mutex_lock(&update_lock); | |
93 | ||
94 | v = inb(DATA_PORT); | |
95 | ||
96 | if (status) | |
97 | outb(v | C2CK, DATA_PORT); | |
98 | else | |
99 | outb(v & ~C2CK, DATA_PORT); | |
100 | ||
101 | mutex_unlock(&update_lock); | |
102 | } | |
103 | ||
104 | static struct c2port_ops duramar2150_c2port_ops = { | |
105 | .block_size = 512, /* bytes */ | |
106 | .blocks_num = 30, /* total flash size: 15360 bytes */ | |
107 | ||
108 | .access = duramar2150_c2port_access, | |
109 | .c2d_dir = duramar2150_c2port_c2d_dir, | |
110 | .c2d_get = duramar2150_c2port_c2d_get, | |
111 | .c2d_set = duramar2150_c2port_c2d_set, | |
112 | .c2ck_set = duramar2150_c2port_c2ck_set, | |
113 | }; | |
114 | ||
115 | static struct c2port_device *duramar2150_c2port_dev; | |
116 | ||
117 | /* | |
118 | * Module stuff | |
119 | */ | |
120 | ||
121 | static int __init duramar2150_c2port_init(void) | |
122 | { | |
123 | struct resource *res; | |
124 | int ret = 0; | |
125 | ||
126 | res = request_region(0x325, 2, "c2port"); | |
127 | if (!res) | |
128 | return -EBUSY; | |
129 | ||
130 | duramar2150_c2port_dev = c2port_device_register("uc", | |
131 | &duramar2150_c2port_ops, NULL); | |
132 | if (!duramar2150_c2port_dev) { | |
133 | ret = -ENODEV; | |
134 | goto free_region; | |
135 | } | |
136 | ||
137 | return 0; | |
138 | ||
139 | free_region: | |
140 | release_region(0x325, 2); | |
141 | return ret; | |
142 | } | |
143 | ||
144 | static void __exit duramar2150_c2port_exit(void) | |
145 | { | |
146 | /* Setup the GPIOs as input by default (access = 0) */ | |
147 | duramar2150_c2port_access(duramar2150_c2port_dev, 0); | |
148 | ||
149 | c2port_device_unregister(duramar2150_c2port_dev); | |
150 | ||
151 | release_region(0x325, 2); | |
152 | } | |
153 | ||
154 | module_init(duramar2150_c2port_init); | |
155 | module_exit(duramar2150_c2port_exit); | |
156 | ||
157 | MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); | |
158 | MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150"); | |
159 | MODULE_LICENSE("GPL"); |