Linux Audio

Check our new training course

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