locomo.c revision e24da5d316667a91b3a19b5761a211946ec649bb
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/arch/arm/common/locomo.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sharp LoCoMo support
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file contains all generic LoCoMo support.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All initialization functions provided here are intended to be called
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from machine specific code with proper arguments when required.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on sa1111.c
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach-types.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach/irq.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware/locomo.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* M62332 output channel selection */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define M62332_EVR_CH	1	/* M62332 volume channel number  */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*   0 : CH.1 , 1 : CH. 2        */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DAC send data */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	M62332_SLAVE_ADDR	0x4e	/* Slave address  */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	M62332_W_BIT		0x00	/* W bit (0 only) */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	M62332_SUB_ADDR		0x00	/* Sub address    */
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	M62332_A_BIT		0x00	/* A bit (0 only) */
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DAC setup and hold times (expressed in us) */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_BUS_FREE_TIME	5	/*   4.7 us */
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_START_SETUP_TIME	5	/*   4.7 us */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_STOP_SETUP_TIME	4	/*   4.0 us */
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_START_HOLD_TIME	5	/*   4.7 us */
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_SCL_LOW_HOLD_TIME	5	/*   4.7 us */
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_SCL_HIGH_HOLD_TIME	4	/*   4.0 us */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_DATA_SETUP_TIME	1	/*   250 ns */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_DATA_HOLD_TIME	1	/*   300 ns */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_LOW_SETUP_TIME	1	/*   300 ns */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DAC_HIGH_SETUP_TIME	1	/*  1000 ns */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the following is the overall data for the locomo chip */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct locomo {
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device *dev;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long phys;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int irq;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *base;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct locomo_dev_info {
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	offset;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	length;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	devid;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	irq[1];
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *	name;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* All the locomo devices.  If offset is non-zero, the mapbase for the
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locomo_dev will be set to the chip base plus offset.  If offset is
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zero, then the mapbase for the locomo_dev will be set to zero.  An
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * offset of zero means the device only uses GPIOs or other helper
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * functions inside this file */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct locomo_dev_info locomo_devices[] = {
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.devid 		= LOCOMO_DEVID_KEYBOARD,
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.irq = {
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			IRQ_LOCOMO_KEY,
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		},
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name		= "locomo-keyboard",
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.offset		= LOCOMO_KEYBOARD,
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.length		= 16,
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.devid		= LOCOMO_DEVID_FRONTLIGHT,
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.irq		= {},
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name		= "locomo-frontlight",
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.offset		= LOCOMO_FRONTLIGHT,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.length		= 8,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.devid		= LOCOMO_DEVID_BACKLIGHT,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.irq		= {},
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name		= "locomo-backlight",
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.offset		= LOCOMO_BACKLIGHT,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.length		= 8,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.devid		= LOCOMO_DEVID_AUDIO,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.irq		= {},
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name		= "locomo-audio",
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.offset		= LOCOMO_AUDIO,
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.length		= 4,
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.devid		= LOCOMO_DEVID_LED,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.irq 		= {},
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name		= "locomo-led",
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.offset		= LOCOMO_LED,
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.length		= 8,
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.devid		= LOCOMO_DEVID_UART,
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.irq		= {},
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name		= "locomo-uart",
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.offset		= 0,
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.length		= 0,
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** LoCoMo interrupt handling stuff.
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: LoCoMo has a 1 to many mapping on all of its IRQs.
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that is, there is only one real hardware interrupt
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we determine which interrupt it is by reading some IO memory.
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have two levels of expansion, first in the handler for the
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware interrupt we generate an interrupt
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ_LOCOMO_*_BASE and those handlers generate more interrupts
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware irq reads LOCOMO_ICR & 0x0f00
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_KEY_BASE
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_GPIO_BASE
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_LT_BASE
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_SPI_BASE
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ_LOCOMO_KEY_BASE reads LOCOMO_KIC & 0x0001
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_KEY
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ_LOCOMO_GPIO_BASE reads LOCOMO_GIR & LOCOMO_GPD & 0xffff
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_GPIO[0-15]
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ_LOCOMO_LT_BASE reads LOCOMO_LTINT & 0x0001
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_LT
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ_LOCOMO_SPI_BASE reads LOCOMO_SPIIR & 0x000F
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_SPI_RFR
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_SPI_RFW
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_SPI_OVRN
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   IRQ_LOCOMO_SPI_TEND
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOCOMO_IRQ_START	(IRQ_LOCOMO_KEY_BASE)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOCOMO_IRQ_KEY_START	(IRQ_LOCOMO_KEY)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LOCOMO_IRQ_GPIO_START	(IRQ_LOCOMO_GPIO0)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LOCOMO_IRQ_LT_START	(IRQ_LOCOMO_LT)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LOCOMO_IRQ_SPI_START	(IRQ_LOCOMO_SPI_RFR)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_handler(unsigned int irq, struct irqdesc *desc,
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct pt_regs *regs)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int req, i;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irqdesc *d;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Acknowledge the parent IRQ */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->chip->ack(irq);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check why this interrupt was generated */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = locomo_readl(mapbase + LOCOMO_ICR) & 0x0f00;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req) {
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* generate the next interrupt(s) */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = LOCOMO_IRQ_START;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d = irq_desc + irq;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= 3; i++, d++, irq++) {
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req & (0x0100 << i)) {
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				d->handle(irq, d, regs);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_ack_irq(unsigned int irq)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_mask_irq(unsigned int irq)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_ICR);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0010 << (irq - LOCOMO_IRQ_START));
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_ICR);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_unmask_irq(unsigned int irq)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_ICR);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0010 << (irq - LOCOMO_IRQ_START));
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_ICR);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irqchip locomo_chip = {
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ack	= locomo_ack_irq,
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mask	= locomo_mask_irq,
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unmask	= locomo_unmask_irq,
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_key_handler(unsigned int irq, struct irqdesc *desc,
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct pt_regs *regs)
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irqdesc *d;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d = irq_desc + LOCOMO_IRQ_KEY_START;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->handle(LOCOMO_IRQ_KEY_START, d, regs);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_key_ack_irq(unsigned int irq)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0100 << (irq - LOCOMO_IRQ_KEY_START));
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_key_mask_irq(unsigned int irq)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0010 << (irq - LOCOMO_IRQ_KEY_START));
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_key_unmask_irq(unsigned int irq)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0010 << (irq - LOCOMO_IRQ_KEY_START));
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irqchip locomo_key_chip = {
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ack	= locomo_key_ack_irq,
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mask	= locomo_key_mask_irq,
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unmask	= locomo_key_unmask_irq,
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc,
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct pt_regs *regs)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int req, i;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irqdesc *d;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = 	locomo_readl(mapbase + LOCOMO_GIR) &
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_readl(mapbase + LOCOMO_GPD) &
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		0xffff;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req) {
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = LOCOMO_IRQ_GPIO_START;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d = irq_desc + LOCOMO_IRQ_GPIO_START;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= 15; i++, irq++, d++) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req & (0x0001 << i)) {
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				d->handle(irq, d, regs);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_gpio_ack_irq(unsigned int irq)
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_GWE);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START));
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_GWE);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_GIS);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START));
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_GIS);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_GWE);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START));
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_GWE);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_gpio_mask_irq(unsigned int irq)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_GIE);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0001 << (irq - LOCOMO_IRQ_GPIO_START));
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_GIE);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_gpio_unmask_irq(unsigned int irq)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_GIE);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0001 << (irq - LOCOMO_IRQ_GPIO_START));
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_GIE);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irqchip locomo_gpio_chip = {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ack	= locomo_gpio_ack_irq,
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mask	= locomo_gpio_mask_irq,
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unmask	= locomo_gpio_unmask_irq,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_lt_handler(unsigned int irq, struct irqdesc *desc,
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct pt_regs *regs)
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irqdesc *d;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) {
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d = irq_desc + LOCOMO_IRQ_LT_START;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->handle(LOCOMO_IRQ_LT_START, d, regs);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_lt_ack_irq(unsigned int irq)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_LTINT);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0100 << (irq - LOCOMO_IRQ_LT_START));
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_LTINT);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_lt_mask_irq(unsigned int irq)
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_LTINT);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0010 << (irq - LOCOMO_IRQ_LT_START));
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_LTINT);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_lt_unmask_irq(unsigned int irq)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_LTINT);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0010 << (irq - LOCOMO_IRQ_LT_START));
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_LTINT);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irqchip locomo_lt_chip = {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ack	= locomo_lt_ack_irq,
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mask	= locomo_lt_mask_irq,
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unmask	= locomo_lt_unmask_irq,
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_spi_handler(unsigned int irq, struct irqdesc *desc,
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct pt_regs *regs)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int req, i;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irqdesc *d;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = locomo_readl(mapbase + LOCOMO_SPIIR) & 0x000F;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req) {
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = LOCOMO_IRQ_SPI_START;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d = irq_desc + irq;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i <= 3; i++, irq++, d++) {
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req & (0x0001 << i)) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				d->handle(irq, d, regs);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_spi_ack_irq(unsigned int irq)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_SPIWE);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START));
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_SPIWE);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_SPIIS);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_SPIIS);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_SPIWE);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_SPIWE);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_spi_mask_irq(unsigned int irq)
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_SPIIE);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_SPIIE);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_spi_unmask_irq(unsigned int irq)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = get_irq_chipdata(irq);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_SPIIE);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START));
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_SPIIE);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irqchip locomo_spi_chip = {
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ack	= locomo_spi_ack_irq,
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mask	= locomo_spi_mask_irq,
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unmask	= locomo_spi_unmask_irq,
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_setup_irq(struct locomo *lchip)
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int irq;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *irqbase = lchip->base;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Install handler for IRQ_LOCOMO_HW.
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_type(lchip->irq, IRQT_FALLING);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(lchip->irq, irqbase);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chained_handler(lchip->irq, locomo_handler);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Install handlers for IRQ_LOCOMO_*_BASE */
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chip(IRQ_LOCOMO_KEY_BASE, &locomo_chip);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(IRQ_LOCOMO_KEY_BASE, irqbase);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chained_handler(IRQ_LOCOMO_KEY_BASE, locomo_key_handler);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_flags(IRQ_LOCOMO_KEY_BASE, IRQF_VALID | IRQF_PROBE);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chip(IRQ_LOCOMO_GPIO_BASE, &locomo_chip);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(IRQ_LOCOMO_GPIO_BASE, irqbase);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chained_handler(IRQ_LOCOMO_GPIO_BASE, locomo_gpio_handler);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_flags(IRQ_LOCOMO_GPIO_BASE, IRQF_VALID | IRQF_PROBE);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chip(IRQ_LOCOMO_LT_BASE, &locomo_chip);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(IRQ_LOCOMO_LT_BASE, irqbase);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chained_handler(IRQ_LOCOMO_LT_BASE, locomo_lt_handler);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_flags(IRQ_LOCOMO_LT_BASE, IRQF_VALID | IRQF_PROBE);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chip(IRQ_LOCOMO_SPI_BASE, &locomo_chip);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(IRQ_LOCOMO_SPI_BASE, irqbase);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chained_handler(IRQ_LOCOMO_SPI_BASE, locomo_spi_handler);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_flags(IRQ_LOCOMO_SPI_BASE, IRQF_VALID | IRQF_PROBE);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install handlers for IRQ_LOCOMO_KEY_BASE generated interrupts */
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chip(LOCOMO_IRQ_KEY_START, &locomo_key_chip);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(LOCOMO_IRQ_KEY_START, irqbase);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_handler(LOCOMO_IRQ_KEY_START, do_edge_IRQ);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_flags(LOCOMO_IRQ_KEY_START, IRQF_VALID | IRQF_PROBE);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install handlers for IRQ_LOCOMO_GPIO_BASE generated interrupts */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (irq = LOCOMO_IRQ_GPIO_START; irq < LOCOMO_IRQ_GPIO_START + 16; irq++) {
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_chip(irq, &locomo_gpio_chip);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_chipdata(irq, irqbase);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_handler(irq, do_edge_IRQ);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install handlers for IRQ_LOCOMO_LT_BASE generated interrupts */
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chip(LOCOMO_IRQ_LT_START, &locomo_lt_chip);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_chipdata(LOCOMO_IRQ_LT_START, irqbase);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_handler(LOCOMO_IRQ_LT_START, do_edge_IRQ);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_irq_flags(LOCOMO_IRQ_LT_START, IRQF_VALID | IRQF_PROBE);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install handlers for IRQ_LOCOMO_SPI_BASE generated interrupts */
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (irq = LOCOMO_IRQ_SPI_START; irq < LOCOMO_IRQ_SPI_START + 3; irq++) {
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_chip(irq, &locomo_spi_chip);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_chipdata(irq, irqbase);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_handler(irq, do_edge_IRQ);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_dev_release(struct device *_dev)
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *dev = LOCOMO_DEV(_dev);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(dev);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslocomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info)
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *dev;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = kmalloc(sizeof(struct locomo_dev), GFP_KERNEL);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev) {
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(dev, 0, sizeof(struct locomo_dev));
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strncpy(dev->dev.bus_id,info->name,sizeof(dev->dev.bus_id));
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If the parent device has a DMA mask associated with it,
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * propagate it down to the children.
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lchip->dev->dma_mask) {
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dma_mask = *lchip->dev->dma_mask;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev.dma_mask = &dev->dma_mask;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->devid	 = info->devid;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->dev.parent  = lchip->dev;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->dev.bus     = &locomo_bus_type;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->dev.release = locomo_dev_release;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (info->offset)
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->mapbase = lchip->base + info->offset;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->mapbase = 0;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->length = info->length;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memmove(dev->irq, info->irq, sizeof(dev->irq));
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = device_register(&dev->dev);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(dev);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	locomo_probe - probe for a single LoCoMo chip.
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@phys_addr: physical address of device.
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Probe for a LoCoMo chip.  This must be called
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	before any other locomo-specific code.
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns:
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	%-ENODEV	device not found.
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	%-EBUSY		physical address already marked in-use.
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	%0		successful.
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__locomo_probe(struct device *me, struct resource *mem, int irq)
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long r;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, ret = -ENODEV;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lchip = kmalloc(sizeof(struct locomo), GFP_KERNEL);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!lchip)
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(lchip, 0, sizeof(struct locomo));
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&lchip->lock);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lchip->dev = me;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_set_drvdata(lchip->dev, lchip);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lchip->phys = mem->start;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lchip->irq = irq;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Map the whole region.  This also maps the
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * registers for our children.
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lchip->base = ioremap(mem->start, PAGE_SIZE);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!lchip->base) {
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* locomo initialize */
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_ICR);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* KEYBOARD */
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* GPIO */
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_GPO);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14))
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			, lchip->base + LOCOMO_GPE);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel( (LOCOMO_GPIO(2) | LOCOMO_GPIO(3) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14))
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			, lchip->base + LOCOMO_GPD);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_GIE);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FrontLight */
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Longtime timer */
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_LTINT);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SPI */
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0, lchip->base + LOCOMO_SPIIE);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_ASD);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= 0x8000;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_ASD);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_HSD);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= 0x8000;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_HSD);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(128 / 8, lchip->base + LOCOMO_HSC);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XON */
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(0x80, lchip->base + LOCOMO_TADC);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(1000);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* CLK9MEN */
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_TADC);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= 0x10;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_TADC);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(100);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* init DAC */
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_DAC);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_DAC);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_VER);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff));
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The interrupt controller must be initialised before any
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * other device to ensure that the interrupts are available.
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lchip->irq != NO_IRQ)
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_setup_irq(lchip);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < ARRAY_SIZE(locomo_devices); i++)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_init_one_child(lchip, &locomo_devices[i]);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(lchip);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
654e24da5d316667a91b3a19b5761a211946ec649bbPavel Machekstatic int locomo_remove_child(struct device *dev, void *data)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
656e24da5d316667a91b3a19b5761a211946ec649bbPavel Machek	device_unregister(dev);
657e24da5d316667a91b3a19b5761a211946ec649bbPavel Machek	return 0;
658e24da5d316667a91b3a19b5761a211946ec649bbPavel Machek}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
660e24da5d316667a91b3a19b5761a211946ec649bbPavel Machekstatic void __locomo_remove(struct locomo *lchip)
661e24da5d316667a91b3a19b5761a211946ec649bbPavel Machek{
662e24da5d316667a91b3a19b5761a211946ec649bbPavel Machek	device_for_each_child(lchip->dev, NULL, locomo_remove_child);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lchip->irq != NO_IRQ) {
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_chained_handler(lchip->irq, NULL);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_irq_data(lchip->irq, NULL);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(lchip->base);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(lchip);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_probe(struct device *dev)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct platform_device *pdev = to_platform_device(dev);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct resource *mem;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int irq;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!mem)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq = platform_get_irq(pdev, 0);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return __locomo_probe(dev, mem, irq);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_remove(struct device *dev)
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip = dev_get_drvdata(dev);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lchip) {
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__locomo_remove(lchip);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_set_drvdata(dev, NULL);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Not sure if this should be on the system bus or not yet.
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	We really want some way to register a system device at
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the per-machine level, and then have this driver pick
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	up the registered devices.
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct device_driver locomo_device_driver = {
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "locomo",
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bus		= &platform_bus_type,
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= locomo_probe,
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= locomo_remove,
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Get the parent device driver (us) structure
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	from a child function device
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (struct locomo *)dev_get_drvdata(ldev->dev.parent);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir)
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip = locomo_chip_driver(ldev);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lchip->lock, flags);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_GPD);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &= ~bits;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_GPD);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_GPE);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dir)
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r |= bits;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r &= ~bits;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_GPE);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lchip->lock, flags);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits)
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip = locomo_chip_driver(ldev);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ret;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lchip->lock, flags);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = locomo_readl(lchip->base + LOCOMO_GPL);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lchip->lock, flags);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret &= bits;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits)
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip = locomo_chip_driver(ldev);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ret;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lchip->lock, flags);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = locomo_readl(lchip->base + LOCOMO_GPO);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lchip->lock, flags);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret &= bits;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set)
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip = locomo_chip_driver(ldev);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lchip->lock, flags);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(lchip->base + LOCOMO_GPO);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r |= bits;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r &= ~bits;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, lchip->base + LOCOMO_GPO);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lchip->lock, flags);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void locomo_m62332_sendbit(void *mapbase, int bit)
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SCLOEB);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_DATA_HOLD_TIME);	/* 300 nsec */
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SCLOEB);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bit & 1) {
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r = locomo_readl(mapbase + LOCOMO_DAC);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r |=  LOCOMO_DAC_SDAOEB;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_writel(r, mapbase + LOCOMO_DAC);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r = locomo_readl(mapbase + LOCOMO_DAC);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r &=  ~(LOCOMO_DAC_SDAOEB);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_writel(r, mapbase + LOCOMO_DAC);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_DATA_SETUP_TIME);	/* 250 nsec */
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/*  4.0 usec */
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel)
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo *lchip = locomo_chip_driver(ldev);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char data;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int r;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *mapbase = lchip->base;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lchip->lock, flags);
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start */
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_BUS_FREE_TIME);	/* 5.0 usec */
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.0 usec */
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SDAOEB);
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_START_HOLD_TIME);	/* 5.0 usec */
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_DATA_HOLD_TIME);	/* 300 nsec */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Send slave address and W bit (LSB is W bit) */
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i <= 8; i++) {
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_m62332_sendbit(mapbase, data >> (8 - i));
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check A bit */
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SCLOEB);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SDAOEB);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "locomo: m62332_senddata Error 1\n");
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Send Sub address (LSB is channel select) */
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*    channel = 0 : ch1 select              */
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*            = 1 : ch2 select              */
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = M62332_SUB_ADDR + channel;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i <= 8; i++) {
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_m62332_sendbit(mapbase, data >> (8 - i));
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check A bit */
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SCLOEB);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SDAOEB);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "locomo: m62332_senddata Error 2\n");
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Send DAC data */
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i <= 8; i++) {
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		locomo_m62332_sendbit(mapbase, dac_data >> (8 - i));
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check A bit */
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SCLOEB);
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SDAOEB);
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "locomo: m62332_senddata Error 3\n");
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* stop */
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r &=  ~(LOCOMO_DAC_SCLOEB);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4 usec */
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SDAOEB;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4 usec */
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = locomo_readl(mapbase + LOCOMO_DAC);
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r |=  LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	locomo_writel(r, mapbase + LOCOMO_DAC);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_LOW_SETUP_TIME);	/* 1000 nsec */
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lchip->lock, flags);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	LoCoMo "Register Access Bus."
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	We model this as a regular bus type, and hang devices directly
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	off this.
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_match(struct device *_dev, struct device_driver *_drv)
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *dev = LOCOMO_DEV(_dev);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_driver *drv = LOCOMO_DRV(_drv);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev->devid == drv->devid;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_bus_suspend(struct device *dev, pm_message_t state)
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *ldev = LOCOMO_DEV(dev);
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drv && drv->suspend)
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = drv->suspend(ldev, state);
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_bus_resume(struct device *dev)
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *ldev = LOCOMO_DEV(dev);
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drv && drv->resume)
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = drv->resume(ldev);
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_bus_probe(struct device *dev)
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *ldev = LOCOMO_DEV(dev);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = -ENODEV;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drv->probe)
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = drv->probe(ldev);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int locomo_bus_remove(struct device *dev)
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_dev *ldev = LOCOMO_DEV(dev);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drv->remove)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = drv->remove(ldev);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct bus_type locomo_bus_type = {
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "locomo-bus",
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.match		= locomo_match,
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.suspend	= locomo_bus_suspend,
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.resume		= locomo_bus_resume,
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint locomo_driver_register(struct locomo_driver *driver)
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->drv.probe = locomo_bus_probe;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->drv.remove = locomo_bus_remove;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->drv.bus = &locomo_bus_type;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return driver_register(&driver->drv);
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid locomo_driver_unregister(struct locomo_driver *driver)
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister(&driver->drv);
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init locomo_init(void)
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = bus_register(&locomo_bus_type);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret == 0)
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		driver_register(&locomo_device_driver);
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit locomo_exit(void)
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister(&locomo_device_driver);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bus_unregister(&locomo_bus_type);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(locomo_init);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(locomo_exit);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Sharp LoCoMo core driver");
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_driver_register);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_driver_unregister);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_gpio_set_dir);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_gpio_read_level);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_gpio_read_output);
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_gpio_write);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(locomo_m62332_senddata);
1059