diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-elektor.c')
-rw-r--r-- | drivers/i2c/busses/i2c-elektor.c | 138 |
1 files changed, 84 insertions, 54 deletions
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 6930b660e508..59f8308c2356 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c | |||
@@ -22,7 +22,7 @@ | |||
22 | /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even | 22 | /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even |
23 | Frodo Looijaard <frodol@dds.nl> */ | 23 | Frodo Looijaard <frodol@dds.nl> */ |
24 | 24 | ||
25 | /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of | 25 | /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of |
26 | for Alpha Processor Inc. UP-2000(+) boards */ | 26 | for Alpha Processor Inc. UP-2000(+) boards */ |
27 | 27 | ||
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
@@ -46,12 +46,14 @@ | |||
46 | #define DEFAULT_BASE 0x330 | 46 | #define DEFAULT_BASE 0x330 |
47 | 47 | ||
48 | static int base; | 48 | static int base; |
49 | static u8 __iomem *base_iomem; | ||
50 | |||
49 | static int irq; | 51 | static int irq; |
50 | static int clock = 0x1c; | 52 | static int clock = 0x1c; |
51 | static int own = 0x55; | 53 | static int own = 0x55; |
52 | static int mmapped; | 54 | static int mmapped; |
53 | 55 | ||
54 | /* vdovikin: removed static struct i2c_pcf_isa gpi; code - | 56 | /* vdovikin: removed static struct i2c_pcf_isa gpi; code - |
55 | this module in real supports only one device, due to missing arguments | 57 | this module in real supports only one device, due to missing arguments |
56 | in some functions, called from the algo-pcf module. Sometimes it's | 58 | in some functions, called from the algo-pcf module. Sometimes it's |
57 | need to be rewriten - but for now just remove this for simpler reading */ | 59 | need to be rewriten - but for now just remove this for simpler reading */ |
@@ -60,40 +62,33 @@ static wait_queue_head_t pcf_wait; | |||
60 | static int pcf_pending; | 62 | static int pcf_pending; |
61 | static spinlock_t lock; | 63 | static spinlock_t lock; |
62 | 64 | ||
65 | static struct i2c_adapter pcf_isa_ops; | ||
66 | |||
63 | /* ----- local functions ---------------------------------------------- */ | 67 | /* ----- local functions ---------------------------------------------- */ |
64 | 68 | ||
65 | static void pcf_isa_setbyte(void *data, int ctl, int val) | 69 | static void pcf_isa_setbyte(void *data, int ctl, int val) |
66 | { | 70 | { |
67 | int address = ctl ? (base + 1) : base; | 71 | u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; |
68 | 72 | ||
69 | /* enable irq if any specified for serial operation */ | 73 | /* enable irq if any specified for serial operation */ |
70 | if (ctl && irq && (val & I2C_PCF_ESO)) { | 74 | if (ctl && irq && (val & I2C_PCF_ESO)) { |
71 | val |= I2C_PCF_ENI; | 75 | val |= I2C_PCF_ENI; |
72 | } | 76 | } |
73 | 77 | ||
74 | pr_debug("i2c-elektor: Write 0x%X 0x%02X\n", address, val & 255); | 78 | pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val); |
75 | 79 | iowrite8(val, address); | |
76 | switch (mmapped) { | 80 | #ifdef __alpha__ |
77 | case 0: /* regular I/O */ | 81 | /* API UP2000 needs some hardware fudging to make the write stick */ |
78 | outb(val, address); | 82 | iowrite8(val, address); |
79 | break; | 83 | #endif |
80 | case 2: /* double mapped I/O needed for UP2000 board, | ||
81 | I don't know why this... */ | ||
82 | writeb(val, (void *)address); | ||
83 | /* fall */ | ||
84 | case 1: /* memory mapped I/O */ | ||
85 | writeb(val, (void *)address); | ||
86 | break; | ||
87 | } | ||
88 | } | 84 | } |
89 | 85 | ||
90 | static int pcf_isa_getbyte(void *data, int ctl) | 86 | static int pcf_isa_getbyte(void *data, int ctl) |
91 | { | 87 | { |
92 | int address = ctl ? (base + 1) : base; | 88 | u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; |
93 | int val = mmapped ? readb((void *)address) : inb(address); | 89 | int val = ioread8(address); |
94 | |||
95 | pr_debug("i2c-elektor: Read 0x%X 0x%02X\n", address, val); | ||
96 | 90 | ||
91 | pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val); | ||
97 | return (val); | 92 | return (val); |
98 | } | 93 | } |
99 | 94 | ||
@@ -149,16 +144,40 @@ static int pcf_isa_init(void) | |||
149 | { | 144 | { |
150 | spin_lock_init(&lock); | 145 | spin_lock_init(&lock); |
151 | if (!mmapped) { | 146 | if (!mmapped) { |
152 | if (!request_region(base, 2, "i2c (isa bus adapter)")) { | 147 | if (!request_region(base, 2, pcf_isa_ops.name)) { |
153 | printk(KERN_ERR | 148 | printk(KERN_ERR "%s: requested I/O region (%#x:2) is " |
154 | "i2c-elektor: requested I/O region (0x%X:2) " | 149 | "in use\n", pcf_isa_ops.name, base); |
155 | "is in use.\n", base); | 150 | return -ENODEV; |
151 | } | ||
152 | base_iomem = ioport_map(base, 2); | ||
153 | if (!base_iomem) { | ||
154 | printk(KERN_ERR "%s: remap of I/O region %#x failed\n", | ||
155 | pcf_isa_ops.name, base); | ||
156 | release_region(base, 2); | ||
157 | return -ENODEV; | ||
158 | } | ||
159 | } else { | ||
160 | if (!request_mem_region(base, 2, pcf_isa_ops.name)) { | ||
161 | printk(KERN_ERR "%s: requested memory region (%#x:2) " | ||
162 | "is in use\n", pcf_isa_ops.name, base); | ||
163 | return -ENODEV; | ||
164 | } | ||
165 | base_iomem = ioremap(base, 2); | ||
166 | if (base_iomem == NULL) { | ||
167 | printk(KERN_ERR "%s: remap of memory region %#x " | ||
168 | "failed\n", pcf_isa_ops.name, base); | ||
169 | release_mem_region(base, 2); | ||
156 | return -ENODEV; | 170 | return -ENODEV; |
157 | } | 171 | } |
158 | } | 172 | } |
173 | pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base, | ||
174 | base_iomem); | ||
175 | |||
159 | if (irq > 0) { | 176 | if (irq > 0) { |
160 | if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", NULL) < 0) { | 177 | if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name, |
161 | printk(KERN_ERR "i2c-elektor: Request irq%d failed\n", irq); | 178 | NULL) < 0) { |
179 | printk(KERN_ERR "%s: Request irq%d failed\n", | ||
180 | pcf_isa_ops.name, irq); | ||
162 | irq = 0; | 181 | irq = 0; |
163 | } else | 182 | } else |
164 | enable_irq(irq); | 183 | enable_irq(irq); |
@@ -186,47 +205,49 @@ static struct i2c_adapter pcf_isa_ops = { | |||
186 | .class = I2C_CLASS_HWMON, | 205 | .class = I2C_CLASS_HWMON, |
187 | .id = I2C_HW_P_ELEK, | 206 | .id = I2C_HW_P_ELEK, |
188 | .algo_data = &pcf_isa_data, | 207 | .algo_data = &pcf_isa_data, |
189 | .name = "PCF8584 ISA adapter", | 208 | .name = "i2c-elektor", |
190 | }; | 209 | }; |
191 | 210 | ||
192 | static int __init i2c_pcfisa_init(void) | 211 | static int __init i2c_pcfisa_init(void) |
193 | { | 212 | { |
194 | #ifdef __alpha__ | 213 | #ifdef __alpha__ |
195 | /* check to see we have memory mapped PCF8584 connected to the | 214 | /* check to see we have memory mapped PCF8584 connected to the |
196 | Cypress cy82c693 PCI-ISA bridge as on UP2000 board */ | 215 | Cypress cy82c693 PCI-ISA bridge as on UP2000 board */ |
197 | if (base == 0) { | 216 | if (base == 0) { |
198 | struct pci_dev *cy693_dev; | 217 | struct pci_dev *cy693_dev; |
199 | 218 | ||
200 | cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, | 219 | cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, |
201 | PCI_DEVICE_ID_CONTAQ_82C693, NULL); | 220 | PCI_DEVICE_ID_CONTAQ_82C693, NULL); |
202 | if (cy693_dev) { | 221 | if (cy693_dev) { |
203 | char config; | 222 | unsigned char config; |
204 | /* yeap, we've found cypress, let's check config */ | 223 | /* yeap, we've found cypress, let's check config */ |
205 | if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { | 224 | if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { |
206 | 225 | ||
207 | pr_debug("i2c-elektor: found cy82c693, config register 0x47 = 0x%02x.\n", config); | 226 | pr_debug("%s: found cy82c693, config " |
227 | "register 0x47 = 0x%02x\n", | ||
228 | pcf_isa_ops.name, config); | ||
208 | 229 | ||
209 | /* UP2000 board has this register set to 0xe1, | 230 | /* UP2000 board has this register set to 0xe1, |
210 | but the most significant bit as seems can be | 231 | but the most significant bit as seems can be |
211 | reset during the proper initialisation | 232 | reset during the proper initialisation |
212 | sequence if guys from API decides to do that | 233 | sequence if guys from API decides to do that |
213 | (so, we can even enable Tsunami Pchip | 234 | (so, we can even enable Tsunami Pchip |
214 | window for the upper 1 Gb) */ | 235 | window for the upper 1 Gb) */ |
215 | 236 | ||
216 | /* so just check for ROMCS at 0xe0000, | 237 | /* so just check for ROMCS at 0xe0000, |
217 | ROMCS enabled for writes | 238 | ROMCS enabled for writes |
218 | and external XD Bus buffer in use. */ | 239 | and external XD Bus buffer in use. */ |
219 | if ((config & 0x7f) == 0x61) { | 240 | if ((config & 0x7f) == 0x61) { |
220 | /* seems to be UP2000 like board */ | 241 | /* seems to be UP2000 like board */ |
221 | base = 0xe0000; | 242 | base = 0xe0000; |
222 | /* I don't know why we need to | 243 | mmapped = 1; |
223 | write twice */ | 244 | /* UP2000 drives ISA with |
224 | mmapped = 2; | ||
225 | /* UP2000 drives ISA with | ||
226 | 8.25 MHz (PCI/4) clock | 245 | 8.25 MHz (PCI/4) clock |
227 | (this can be read from cypress) */ | 246 | (this can be read from cypress) */ |
228 | clock = I2C_PCF_CLK | I2C_PCF_TRNS90; | 247 | clock = I2C_PCF_CLK | I2C_PCF_TRNS90; |
229 | printk(KERN_INFO "i2c-elektor: found API UP2000 like board, will probe PCF8584 later.\n"); | 248 | pr_info("%s: found API UP2000 like " |
249 | "board, will probe PCF8584 " | ||
250 | "later\n", pcf_isa_ops.name); | ||
230 | } | 251 | } |
231 | } | 252 | } |
232 | pci_dev_put(cy693_dev); | 253 | pci_dev_put(cy693_dev); |
@@ -236,12 +257,11 @@ static int __init i2c_pcfisa_init(void) | |||
236 | 257 | ||
237 | /* sanity checks for mmapped I/O */ | 258 | /* sanity checks for mmapped I/O */ |
238 | if (mmapped && base < 0xc8000) { | 259 | if (mmapped && base < 0xc8000) { |
239 | printk(KERN_ERR "i2c-elektor: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); | 260 | printk(KERN_ERR "%s: incorrect base address (%#x) specified " |
261 | "for mmapped I/O\n", pcf_isa_ops.name, base); | ||
240 | return -ENODEV; | 262 | return -ENODEV; |
241 | } | 263 | } |
242 | 264 | ||
243 | printk(KERN_INFO "i2c-elektor: i2c pcf8584-isa adapter driver\n"); | ||
244 | |||
245 | if (base == 0) { | 265 | if (base == 0) { |
246 | base = DEFAULT_BASE; | 266 | base = DEFAULT_BASE; |
247 | } | 267 | } |
@@ -251,8 +271,8 @@ static int __init i2c_pcfisa_init(void) | |||
251 | return -ENODEV; | 271 | return -ENODEV; |
252 | if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) | 272 | if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) |
253 | goto fail; | 273 | goto fail; |
254 | 274 | ||
255 | printk(KERN_ERR "i2c-elektor: found device at %#x.\n", base); | 275 | dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base); |
256 | 276 | ||
257 | return 0; | 277 | return 0; |
258 | 278 | ||
@@ -262,8 +282,13 @@ static int __init i2c_pcfisa_init(void) | |||
262 | free_irq(irq, NULL); | 282 | free_irq(irq, NULL); |
263 | } | 283 | } |
264 | 284 | ||
265 | if (!mmapped) | 285 | if (!mmapped) { |
266 | release_region(base , 2); | 286 | ioport_unmap(base_iomem); |
287 | release_region(base, 2); | ||
288 | } else { | ||
289 | iounmap(base_iomem); | ||
290 | release_mem_region(base, 2); | ||
291 | } | ||
267 | return -ENODEV; | 292 | return -ENODEV; |
268 | } | 293 | } |
269 | 294 | ||
@@ -276,8 +301,13 @@ static void i2c_pcfisa_exit(void) | |||
276 | free_irq(irq, NULL); | 301 | free_irq(irq, NULL); |
277 | } | 302 | } |
278 | 303 | ||
279 | if (!mmapped) | 304 | if (!mmapped) { |
280 | release_region(base , 2); | 305 | ioport_unmap(base_iomem); |
306 | release_region(base, 2); | ||
307 | } else { | ||
308 | iounmap(base_iomem); | ||
309 | release_mem_region(base, 2); | ||
310 | } | ||
281 | } | 311 | } |
282 | 312 | ||
283 | MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); | 313 | MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); |