]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/i2c/busses/i2c-elektor.c
x86/speculation/mds: Add mitigation control for MDS
[mirror_ubuntu-bionic-kernel.git] / drivers / i2c / busses / i2c-elektor.c
CommitLineData
1da177e4
LT
1/* ------------------------------------------------------------------------- */
2/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */
3/* ------------------------------------------------------------------------- */
4/* Copyright (C) 1995-97 Simon G. Vogl
5 1998-99 Hans Berglund
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ca1f8da9 15 GNU General Public License for more details. */
1da177e4
LT
16/* ------------------------------------------------------------------------- */
17
96de0e25 18/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
1da177e4
LT
19 Frodo Looijaard <frodol@dds.nl> */
20
25985edc 21/* Partially rewriten by Oleg I. Vdovikin for mmapped support of
1da177e4
LT
22 for Alpha Processor Inc. UP-2000(+) boards */
23
1da177e4
LT
24#include <linux/kernel.h>
25#include <linux/ioport.h>
26#include <linux/module.h>
27#include <linux/delay.h>
1da177e4
LT
28#include <linux/init.h>
29#include <linux/interrupt.h>
30#include <linux/pci.h>
31#include <linux/wait.h>
32
4a5d3030 33#include <linux/isa.h>
1da177e4
LT
34#include <linux/i2c.h>
35#include <linux/i2c-algo-pcf.h>
21782180 36#include <linux/io.h>
1da177e4 37
1da177e4
LT
38#include <asm/irq.h>
39
40#include "../algos/i2c-algo-pcf.h"
41
42#define DEFAULT_BASE 0x330
43
44static int base;
3634ff6a
ST
45static u8 __iomem *base_iomem;
46
1da177e4
LT
47static int irq;
48static int clock = 0x1c;
49static int own = 0x55;
50static int mmapped;
51
fe3d6a99 52/* vdovikin: removed static struct i2c_pcf_isa gpi; code -
1da177e4
LT
53 this module in real supports only one device, due to missing arguments
54 in some functions, called from the algo-pcf module. Sometimes it's
55 need to be rewriten - but for now just remove this for simpler reading */
56
57static wait_queue_head_t pcf_wait;
58static int pcf_pending;
59static spinlock_t lock;
60
fe3d6a99
ST
61static struct i2c_adapter pcf_isa_ops;
62
1da177e4
LT
63/* ----- local functions ---------------------------------------------- */
64
65static void pcf_isa_setbyte(void *data, int ctl, int val)
66{
3634ff6a 67 u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
1da177e4
LT
68
69 /* enable irq if any specified for serial operation */
70 if (ctl && irq && (val & I2C_PCF_ESO)) {
71 val |= I2C_PCF_ENI;
72 }
73
fe3d6a99 74 pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val);
3634ff6a
ST
75 iowrite8(val, address);
76#ifdef __alpha__
77 /* API UP2000 needs some hardware fudging to make the write stick */
78 iowrite8(val, address);
79#endif
1da177e4
LT
80}
81
82static int pcf_isa_getbyte(void *data, int ctl)
83{
3634ff6a
ST
84 u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
85 int val = ioread8(address);
1da177e4 86
fe3d6a99 87 pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val);
1da177e4
LT
88 return (val);
89}
90
91static int pcf_isa_getown(void *data)
92{
93 return (own);
94}
95
96
97static int pcf_isa_getclock(void *data)
98{
99 return (clock);
100}
101
08e5338d
DM
102static void pcf_isa_waitforpin(void *data)
103{
1da177e4
LT
104 DEFINE_WAIT(wait);
105 int timeout = 2;
106 unsigned long flags;
107
108 if (irq > 0) {
109 spin_lock_irqsave(&lock, flags);
110 if (pcf_pending == 0) {
111 spin_unlock_irqrestore(&lock, flags);
112 prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
113 if (schedule_timeout(timeout*HZ)) {
114 spin_lock_irqsave(&lock, flags);
115 if (pcf_pending == 1) {
116 pcf_pending = 0;
117 }
118 spin_unlock_irqrestore(&lock, flags);
119 }
120 finish_wait(&pcf_wait, &wait);
121 } else {
122 pcf_pending = 0;
123 spin_unlock_irqrestore(&lock, flags);
124 }
125 } else {
126 udelay(100);
127 }
128}
129
130
7d12e780 131static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
1da177e4
LT
132 spin_lock(&lock);
133 pcf_pending = 1;
134 spin_unlock(&lock);
135 wake_up_interruptible(&pcf_wait);
136 return IRQ_HANDLED;
137}
138
139
140static int pcf_isa_init(void)
141{
142 spin_lock_init(&lock);
143 if (!mmapped) {
fe3d6a99
ST
144 if (!request_region(base, 2, pcf_isa_ops.name)) {
145 printk(KERN_ERR "%s: requested I/O region (%#x:2) is "
146 "in use\n", pcf_isa_ops.name, base);
1da177e4
LT
147 return -ENODEV;
148 }
3634ff6a
ST
149 base_iomem = ioport_map(base, 2);
150 if (!base_iomem) {
fe3d6a99
ST
151 printk(KERN_ERR "%s: remap of I/O region %#x failed\n",
152 pcf_isa_ops.name, base);
3634ff6a
ST
153 release_region(base, 2);
154 return -ENODEV;
155 }
156 } else {
fe3d6a99
ST
157 if (!request_mem_region(base, 2, pcf_isa_ops.name)) {
158 printk(KERN_ERR "%s: requested memory region (%#x:2) "
159 "is in use\n", pcf_isa_ops.name, base);
3634ff6a
ST
160 return -ENODEV;
161 }
162 base_iomem = ioremap(base, 2);
163 if (base_iomem == NULL) {
fe3d6a99
ST
164 printk(KERN_ERR "%s: remap of memory region %#x "
165 "failed\n", pcf_isa_ops.name, base);
3634ff6a
ST
166 release_mem_region(base, 2);
167 return -ENODEV;
168 }
1da177e4 169 }
fe3d6a99 170 pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base,
3634ff6a
ST
171 base_iomem);
172
1da177e4 173 if (irq > 0) {
fe3d6a99
ST
174 if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name,
175 NULL) < 0) {
176 printk(KERN_ERR "%s: Request irq%d failed\n",
177 pcf_isa_ops.name, irq);
1da177e4
LT
178 irq = 0;
179 } else
180 enable_irq(irq);
181 }
182 return 0;
183}
184
185/* ------------------------------------------------------------------------
186 * Encapsulate the above functions in the correct operations structure.
187 * This is only done when more than one hardware adapter is supported.
188 */
189static struct i2c_algo_pcf_data pcf_isa_data = {
190 .setpcf = pcf_isa_setbyte,
191 .getpcf = pcf_isa_getbyte,
192 .getown = pcf_isa_getown,
193 .getclock = pcf_isa_getclock,
194 .waitforpin = pcf_isa_waitforpin,
1da177e4
LT
195};
196
197static struct i2c_adapter pcf_isa_ops = {
198 .owner = THIS_MODULE,
3401b2ff 199 .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
1da177e4 200 .algo_data = &pcf_isa_data,
fe3d6a99 201 .name = "i2c-elektor",
1da177e4
LT
202};
203
0b255e92 204static int elektor_match(struct device *dev, unsigned int id)
1da177e4
LT
205{
206#ifdef __alpha__
fe3d6a99 207 /* check to see we have memory mapped PCF8584 connected to the
1da177e4
LT
208 Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
209 if (base == 0) {
210 struct pci_dev *cy693_dev;
fe3d6a99
ST
211
212 cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
1da177e4
LT
213 PCI_DEVICE_ID_CONTAQ_82C693, NULL);
214 if (cy693_dev) {
3634ff6a 215 unsigned char config;
1da177e4
LT
216 /* yeap, we've found cypress, let's check config */
217 if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
fe3d6a99 218
4a5d3030
JD
219 dev_dbg(dev, "found cy82c693, config "
220 "register 0x47 = 0x%02x\n", config);
1da177e4
LT
221
222 /* UP2000 board has this register set to 0xe1,
fe3d6a99 223 but the most significant bit as seems can be
1da177e4 224 reset during the proper initialisation
fe3d6a99
ST
225 sequence if guys from API decides to do that
226 (so, we can even enable Tsunami Pchip
227 window for the upper 1 Gb) */
1da177e4
LT
228
229 /* so just check for ROMCS at 0xe0000,
fe3d6a99 230 ROMCS enabled for writes
1da177e4
LT
231 and external XD Bus buffer in use. */
232 if ((config & 0x7f) == 0x61) {
233 /* seems to be UP2000 like board */
234 base = 0xe0000;
3634ff6a 235 mmapped = 1;
fe3d6a99 236 /* UP2000 drives ISA with
1da177e4
LT
237 8.25 MHz (PCI/4) clock
238 (this can be read from cypress) */
239 clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
4a5d3030
JD
240 dev_info(dev, "found API UP2000 like "
241 "board, will probe PCF8584 "
242 "later\n");
1da177e4
LT
243 }
244 }
245 pci_dev_put(cy693_dev);
246 }
247 }
248#endif
249
250 /* sanity checks for mmapped I/O */
251 if (mmapped && base < 0xc8000) {
4a5d3030
JD
252 dev_err(dev, "incorrect base address (%#x) specified "
253 "for mmapped I/O\n", base);
254 return 0;
1da177e4
LT
255 }
256
1da177e4
LT
257 if (base == 0) {
258 base = DEFAULT_BASE;
259 }
4a5d3030
JD
260 return 1;
261}
1da177e4 262
0b255e92 263static int elektor_probe(struct device *dev, unsigned int id)
4a5d3030 264{
1da177e4
LT
265 init_waitqueue_head(&pcf_wait);
266 if (pcf_isa_init())
267 return -ENODEV;
4a5d3030 268 pcf_isa_ops.dev.parent = dev;
1da177e4
LT
269 if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
270 goto fail;
fe3d6a99 271
4a5d3030 272 dev_info(dev, "found device at %#x\n", base);
1da177e4
LT
273
274 return 0;
275
276 fail:
277 if (irq > 0) {
278 disable_irq(irq);
279 free_irq(irq, NULL);
280 }
281
3634ff6a
ST
282 if (!mmapped) {
283 ioport_unmap(base_iomem);
fe3d6a99 284 release_region(base, 2);
3634ff6a
ST
285 } else {
286 iounmap(base_iomem);
287 release_mem_region(base, 2);
288 }
1da177e4
LT
289 return -ENODEV;
290}
291
0b255e92 292static int elektor_remove(struct device *dev, unsigned int id)
1da177e4 293{
3269711b 294 i2c_del_adapter(&pcf_isa_ops);
1da177e4
LT
295
296 if (irq > 0) {
297 disable_irq(irq);
298 free_irq(irq, NULL);
299 }
300
3634ff6a
ST
301 if (!mmapped) {
302 ioport_unmap(base_iomem);
fe3d6a99 303 release_region(base, 2);
3634ff6a
ST
304 } else {
305 iounmap(base_iomem);
306 release_mem_region(base, 2);
307 }
4a5d3030
JD
308
309 return 0;
310}
311
312static struct isa_driver i2c_elektor_driver = {
313 .match = elektor_match,
314 .probe = elektor_probe,
0b255e92 315 .remove = elektor_remove,
4a5d3030
JD
316 .driver = {
317 .owner = THIS_MODULE,
318 .name = "i2c-elektor",
319 },
320};
321
1da177e4
LT
322MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
323MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
324MODULE_LICENSE("GPL");
325
c78babcc
DH
326module_param_hw(base, int, ioport_or_iomem, 0);
327module_param_hw(irq, int, irq, 0);
1da177e4
LT
328module_param(clock, int, 0);
329module_param(own, int, 0);
c78babcc 330module_param_hw(mmapped, int, other, 0);
9e55c073 331module_isa_driver(i2c_elektor_driver, 1);