xref: /openbmc/linux/drivers/mfd/ucb1x00-core.c (revision cae15476)
105c45ca9SRussell King /*
205c45ca9SRussell King  *  linux/drivers/mfd/ucb1x00-core.c
305c45ca9SRussell King  *
405c45ca9SRussell King  *  Copyright (C) 2001 Russell King, All Rights Reserved.
505c45ca9SRussell King  *
605c45ca9SRussell King  * This program is free software; you can redistribute it and/or modify
705c45ca9SRussell King  * it under the terms of the GNU General Public License as published by
805c45ca9SRussell King  * the Free Software Foundation; either version 2 of the License.
905c45ca9SRussell King  *
1005c45ca9SRussell King  *  The UCB1x00 core driver provides basic services for handling IO,
1105c45ca9SRussell King  *  the ADC, interrupts, and accessing registers.  It is designed
1205c45ca9SRussell King  *  such that everything goes through this layer, thereby providing
1305c45ca9SRussell King  *  a consistent locking methodology, as well as allowing the drivers
1405c45ca9SRussell King  *  to be used on other non-MCP-enabled hardware platforms.
1505c45ca9SRussell King  *
1605c45ca9SRussell King  *  Note that all locks are private to this file.  Nothing else may
1705c45ca9SRussell King  *  touch them.
1805c45ca9SRussell King  */
1905c45ca9SRussell King #include <linux/module.h>
2005c45ca9SRussell King #include <linux/kernel.h>
21d43c36dcSAlexey Dobriyan #include <linux/sched.h>
2205c45ca9SRussell King #include <linux/slab.h>
2305c45ca9SRussell King #include <linux/init.h>
2405c45ca9SRussell King #include <linux/errno.h>
2505c45ca9SRussell King #include <linux/interrupt.h>
2605c45ca9SRussell King #include <linux/device.h>
27a621aaedSArjan van de Ven #include <linux/mutex.h>
28c8602edfSThomas Kunze #include <linux/mfd/ucb1x00.h>
299ca3dc80SThomas Kunze #include <linux/gpio.h>
3005c45ca9SRussell King 
31a621aaedSArjan van de Ven static DEFINE_MUTEX(ucb1x00_mutex);
3205c45ca9SRussell King static LIST_HEAD(ucb1x00_drivers);
3305c45ca9SRussell King static LIST_HEAD(ucb1x00_devices);
3405c45ca9SRussell King 
3505c45ca9SRussell King /**
3605c45ca9SRussell King  *	ucb1x00_io_set_dir - set IO direction
3705c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
3805c45ca9SRussell King  *	@in:  bitfield of IO pins to be set as inputs
3905c45ca9SRussell King  *	@out: bitfield of IO pins to be set as outputs
4005c45ca9SRussell King  *
4105c45ca9SRussell King  *	Set the IO direction of the ten general purpose IO pins on
4205c45ca9SRussell King  *	the UCB1x00 chip.  The @in bitfield has priority over the
4305c45ca9SRussell King  *	@out bitfield, in that if you specify a pin as both input
4405c45ca9SRussell King  *	and output, it will end up as an input.
4505c45ca9SRussell King  *
4605c45ca9SRussell King  *	ucb1x00_enable must have been called to enable the comms
4705c45ca9SRussell King  *	before using this function.
4805c45ca9SRussell King  *
4905c45ca9SRussell King  *	This function takes a spinlock, disabling interrupts.
5005c45ca9SRussell King  */
5105c45ca9SRussell King void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out)
5205c45ca9SRussell King {
5305c45ca9SRussell King 	unsigned long flags;
5405c45ca9SRussell King 
5505c45ca9SRussell King 	spin_lock_irqsave(&ucb->io_lock, flags);
5605c45ca9SRussell King 	ucb->io_dir |= out;
5705c45ca9SRussell King 	ucb->io_dir &= ~in;
5805c45ca9SRussell King 
5905c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
6005c45ca9SRussell King 	spin_unlock_irqrestore(&ucb->io_lock, flags);
6105c45ca9SRussell King }
6205c45ca9SRussell King 
6305c45ca9SRussell King /**
6405c45ca9SRussell King  *	ucb1x00_io_write - set or clear IO outputs
6505c45ca9SRussell King  *	@ucb:   UCB1x00 structure describing chip
6605c45ca9SRussell King  *	@set:   bitfield of IO pins to set to logic '1'
6705c45ca9SRussell King  *	@clear: bitfield of IO pins to set to logic '0'
6805c45ca9SRussell King  *
6905c45ca9SRussell King  *	Set the IO output state of the specified IO pins.  The value
7005c45ca9SRussell King  *	is retained if the pins are subsequently configured as inputs.
7105c45ca9SRussell King  *	The @clear bitfield has priority over the @set bitfield -
7205c45ca9SRussell King  *	outputs will be cleared.
7305c45ca9SRussell King  *
7405c45ca9SRussell King  *	ucb1x00_enable must have been called to enable the comms
7505c45ca9SRussell King  *	before using this function.
7605c45ca9SRussell King  *
7705c45ca9SRussell King  *	This function takes a spinlock, disabling interrupts.
7805c45ca9SRussell King  */
7905c45ca9SRussell King void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
8005c45ca9SRussell King {
8105c45ca9SRussell King 	unsigned long flags;
8205c45ca9SRussell King 
8305c45ca9SRussell King 	spin_lock_irqsave(&ucb->io_lock, flags);
8405c45ca9SRussell King 	ucb->io_out |= set;
8505c45ca9SRussell King 	ucb->io_out &= ~clear;
8605c45ca9SRussell King 
8705c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
8805c45ca9SRussell King 	spin_unlock_irqrestore(&ucb->io_lock, flags);
8905c45ca9SRussell King }
9005c45ca9SRussell King 
9105c45ca9SRussell King /**
9205c45ca9SRussell King  *	ucb1x00_io_read - read the current state of the IO pins
9305c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
9405c45ca9SRussell King  *
9505c45ca9SRussell King  *	Return a bitfield describing the logic state of the ten
9605c45ca9SRussell King  *	general purpose IO pins.
9705c45ca9SRussell King  *
9805c45ca9SRussell King  *	ucb1x00_enable must have been called to enable the comms
9905c45ca9SRussell King  *	before using this function.
10005c45ca9SRussell King  *
101cae15476SRussell King  *	This function does not take any mutexes or spinlocks.
10205c45ca9SRussell King  */
10305c45ca9SRussell King unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
10405c45ca9SRussell King {
10505c45ca9SRussell King 	return ucb1x00_reg_read(ucb, UCB_IO_DATA);
10605c45ca9SRussell King }
10705c45ca9SRussell King 
1089ca3dc80SThomas Kunze static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
1099ca3dc80SThomas Kunze {
1109ca3dc80SThomas Kunze 	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
1119ca3dc80SThomas Kunze 	unsigned long flags;
1129ca3dc80SThomas Kunze 
1139ca3dc80SThomas Kunze 	spin_lock_irqsave(&ucb->io_lock, flags);
1149ca3dc80SThomas Kunze 	if (value)
1159ca3dc80SThomas Kunze 		ucb->io_out |= 1 << offset;
1169ca3dc80SThomas Kunze 	else
1179ca3dc80SThomas Kunze 		ucb->io_out &= ~(1 << offset);
1189ca3dc80SThomas Kunze 
1199ca3dc80SThomas Kunze 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
1209ca3dc80SThomas Kunze 	spin_unlock_irqrestore(&ucb->io_lock, flags);
1219ca3dc80SThomas Kunze }
1229ca3dc80SThomas Kunze 
1239ca3dc80SThomas Kunze static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
1249ca3dc80SThomas Kunze {
1259ca3dc80SThomas Kunze 	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
1269ca3dc80SThomas Kunze 	return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
1279ca3dc80SThomas Kunze }
1289ca3dc80SThomas Kunze 
1299ca3dc80SThomas Kunze static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
1309ca3dc80SThomas Kunze {
1319ca3dc80SThomas Kunze 	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
1329ca3dc80SThomas Kunze 	unsigned long flags;
1339ca3dc80SThomas Kunze 
1349ca3dc80SThomas Kunze 	spin_lock_irqsave(&ucb->io_lock, flags);
1359ca3dc80SThomas Kunze 	ucb->io_dir &= ~(1 << offset);
1369ca3dc80SThomas Kunze 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
1379ca3dc80SThomas Kunze 	spin_unlock_irqrestore(&ucb->io_lock, flags);
1389ca3dc80SThomas Kunze 
1399ca3dc80SThomas Kunze 	return 0;
1409ca3dc80SThomas Kunze }
1419ca3dc80SThomas Kunze 
1429ca3dc80SThomas Kunze static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
1439ca3dc80SThomas Kunze 		, int value)
1449ca3dc80SThomas Kunze {
1459ca3dc80SThomas Kunze 	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
1469ca3dc80SThomas Kunze 	unsigned long flags;
147c23bb602SRussell King 	unsigned old, mask = 1 << offset;
1489ca3dc80SThomas Kunze 
1499ca3dc80SThomas Kunze 	spin_lock_irqsave(&ucb->io_lock, flags);
150c23bb602SRussell King 	old = ucb->io_out;
1519ca3dc80SThomas Kunze 	if (value)
152c23bb602SRussell King 		ucb->io_out |= mask;
1539ca3dc80SThomas Kunze 	else
154c23bb602SRussell King 		ucb->io_out &= ~mask;
155c23bb602SRussell King 
156c23bb602SRussell King 	if (old != ucb->io_out)
1579ca3dc80SThomas Kunze 		ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
158c23bb602SRussell King 
159c23bb602SRussell King 	if (!(ucb->io_dir & mask)) {
160c23bb602SRussell King 		ucb->io_dir |= mask;
161c23bb602SRussell King 		ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
162c23bb602SRussell King 	}
1639ca3dc80SThomas Kunze 	spin_unlock_irqrestore(&ucb->io_lock, flags);
1649ca3dc80SThomas Kunze 
1659ca3dc80SThomas Kunze 	return 0;
1669ca3dc80SThomas Kunze }
1679ca3dc80SThomas Kunze 
16805c45ca9SRussell King /*
16905c45ca9SRussell King  * UCB1300 data sheet says we must:
17005c45ca9SRussell King  *  1. enable ADC	=> 5us (including reference startup time)
17105c45ca9SRussell King  *  2. select input	=> 51*tsibclk  => 4.3us
17205c45ca9SRussell King  *  3. start conversion	=> 102*tsibclk => 8.5us
17305c45ca9SRussell King  * (tsibclk = 1/11981000)
17405c45ca9SRussell King  * Period between SIB 128-bit frames = 10.7us
17505c45ca9SRussell King  */
17605c45ca9SRussell King 
17705c45ca9SRussell King /**
17805c45ca9SRussell King  *	ucb1x00_adc_enable - enable the ADC converter
17905c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
18005c45ca9SRussell King  *
18105c45ca9SRussell King  *	Enable the ucb1x00 and ADC converter on the UCB1x00 for use.
18205c45ca9SRussell King  *	Any code wishing to use the ADC converter must call this
18305c45ca9SRussell King  *	function prior to using it.
18405c45ca9SRussell King  *
185cae15476SRussell King  *	This function takes the ADC mutex to prevent two or more
18605c45ca9SRussell King  *	concurrent uses, and therefore may sleep.  As a result, it
18705c45ca9SRussell King  *	can only be called from process context, not interrupt
18805c45ca9SRussell King  *	context.
18905c45ca9SRussell King  *
19005c45ca9SRussell King  *	You should release the ADC as soon as possible using
19105c45ca9SRussell King  *	ucb1x00_adc_disable.
19205c45ca9SRussell King  */
19305c45ca9SRussell King void ucb1x00_adc_enable(struct ucb1x00 *ucb)
19405c45ca9SRussell King {
195cae15476SRussell King 	mutex_lock(&ucb->adc_mutex);
19605c45ca9SRussell King 
19705c45ca9SRussell King 	ucb->adc_cr |= UCB_ADC_ENA;
19805c45ca9SRussell King 
19905c45ca9SRussell King 	ucb1x00_enable(ucb);
20005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
20105c45ca9SRussell King }
20205c45ca9SRussell King 
20305c45ca9SRussell King /**
20405c45ca9SRussell King  *	ucb1x00_adc_read - read the specified ADC channel
20505c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
20605c45ca9SRussell King  *	@adc_channel: ADC channel mask
20705c45ca9SRussell King  *	@sync: wait for syncronisation pulse.
20805c45ca9SRussell King  *
20905c45ca9SRussell King  *	Start an ADC conversion and wait for the result.  Note that
21005c45ca9SRussell King  *	synchronised ADC conversions (via the ADCSYNC pin) must wait
21105c45ca9SRussell King  *	until the trigger is asserted and the conversion is finished.
21205c45ca9SRussell King  *
21305c45ca9SRussell King  *	This function currently spins waiting for the conversion to
21405c45ca9SRussell King  *	complete (2 frames max without sync).
21505c45ca9SRussell King  *
21605c45ca9SRussell King  *	If called for a synchronised ADC conversion, it may sleep
217cae15476SRussell King  *	with the ADC mutex held.
21805c45ca9SRussell King  */
21905c45ca9SRussell King unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
22005c45ca9SRussell King {
22105c45ca9SRussell King 	unsigned int val;
22205c45ca9SRussell King 
22305c45ca9SRussell King 	if (sync)
22405c45ca9SRussell King 		adc_channel |= UCB_ADC_SYNC_ENA;
22505c45ca9SRussell King 
22605c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel);
22705c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
22805c45ca9SRussell King 
22905c45ca9SRussell King 	for (;;) {
23005c45ca9SRussell King 		val = ucb1x00_reg_read(ucb, UCB_ADC_DATA);
23105c45ca9SRussell King 		if (val & UCB_ADC_DAT_VAL)
23205c45ca9SRussell King 			break;
23305c45ca9SRussell King 		/* yield to other processes */
23405c45ca9SRussell King 		set_current_state(TASK_INTERRUPTIBLE);
23505c45ca9SRussell King 		schedule_timeout(1);
23605c45ca9SRussell King 	}
23705c45ca9SRussell King 
23805c45ca9SRussell King 	return UCB_ADC_DAT(val);
23905c45ca9SRussell King }
24005c45ca9SRussell King 
24105c45ca9SRussell King /**
24205c45ca9SRussell King  *	ucb1x00_adc_disable - disable the ADC converter
24305c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
24405c45ca9SRussell King  *
245cae15476SRussell King  *	Disable the ADC converter and release the ADC mutex.
24605c45ca9SRussell King  */
24705c45ca9SRussell King void ucb1x00_adc_disable(struct ucb1x00 *ucb)
24805c45ca9SRussell King {
24905c45ca9SRussell King 	ucb->adc_cr &= ~UCB_ADC_ENA;
25005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
25105c45ca9SRussell King 	ucb1x00_disable(ucb);
25205c45ca9SRussell King 
253cae15476SRussell King 	mutex_unlock(&ucb->adc_mutex);
25405c45ca9SRussell King }
25505c45ca9SRussell King 
25605c45ca9SRussell King /*
25705c45ca9SRussell King  * UCB1x00 Interrupt handling.
25805c45ca9SRussell King  *
25905c45ca9SRussell King  * The UCB1x00 can generate interrupts when the SIBCLK is stopped.
26005c45ca9SRussell King  * Since we need to read an internal register, we must re-enable
26105c45ca9SRussell King  * SIBCLK to talk to the chip.  We leave the clock running until
26205c45ca9SRussell King  * we have finished processing all interrupts from the chip.
26305c45ca9SRussell King  */
2647d12e780SDavid Howells static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
26505c45ca9SRussell King {
26605c45ca9SRussell King 	struct ucb1x00 *ucb = devid;
26705c45ca9SRussell King 	struct ucb1x00_irq *irq;
26805c45ca9SRussell King 	unsigned int isr, i;
26905c45ca9SRussell King 
27005c45ca9SRussell King 	ucb1x00_enable(ucb);
27105c45ca9SRussell King 	isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
27205c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
27305c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
27405c45ca9SRussell King 
27505c45ca9SRussell King 	for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
27605c45ca9SRussell King 		if (isr & 1 && irq->fn)
27705c45ca9SRussell King 			irq->fn(i, irq->devid);
27805c45ca9SRussell King 	ucb1x00_disable(ucb);
27905c45ca9SRussell King 
28005c45ca9SRussell King 	return IRQ_HANDLED;
28105c45ca9SRussell King }
28205c45ca9SRussell King 
28305c45ca9SRussell King /**
28405c45ca9SRussell King  *	ucb1x00_hook_irq - hook a UCB1x00 interrupt
28505c45ca9SRussell King  *	@ucb:   UCB1x00 structure describing chip
28605c45ca9SRussell King  *	@idx:   interrupt index
28705c45ca9SRussell King  *	@fn:    function to call when interrupt is triggered
28805c45ca9SRussell King  *	@devid: device id to pass to interrupt handler
28905c45ca9SRussell King  *
29005c45ca9SRussell King  *	Hook the specified interrupt.  You can only register one handler
29105c45ca9SRussell King  *	for each interrupt source.  The interrupt source is not enabled
29205c45ca9SRussell King  *	by this function; use ucb1x00_enable_irq instead.
29305c45ca9SRussell King  *
29405c45ca9SRussell King  *	Interrupt handlers will be called with other interrupts enabled.
29505c45ca9SRussell King  *
29605c45ca9SRussell King  *	Returns zero on success, or one of the following errors:
29705c45ca9SRussell King  *	 -EINVAL if the interrupt index is invalid
29805c45ca9SRussell King  *	 -EBUSY if the interrupt has already been hooked
29905c45ca9SRussell King  */
30005c45ca9SRussell King int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
30105c45ca9SRussell King {
30205c45ca9SRussell King 	struct ucb1x00_irq *irq;
30305c45ca9SRussell King 	int ret = -EINVAL;
30405c45ca9SRussell King 
30505c45ca9SRussell King 	if (idx < 16) {
30605c45ca9SRussell King 		irq = ucb->irq_handler + idx;
30705c45ca9SRussell King 		ret = -EBUSY;
30805c45ca9SRussell King 
30905c45ca9SRussell King 		spin_lock_irq(&ucb->lock);
31005c45ca9SRussell King 		if (irq->fn == NULL) {
31105c45ca9SRussell King 			irq->devid = devid;
31205c45ca9SRussell King 			irq->fn = fn;
31305c45ca9SRussell King 			ret = 0;
31405c45ca9SRussell King 		}
31505c45ca9SRussell King 		spin_unlock_irq(&ucb->lock);
31605c45ca9SRussell King 	}
31705c45ca9SRussell King 	return ret;
31805c45ca9SRussell King }
31905c45ca9SRussell King 
32005c45ca9SRussell King /**
32105c45ca9SRussell King  *	ucb1x00_enable_irq - enable an UCB1x00 interrupt source
32205c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
32305c45ca9SRussell King  *	@idx: interrupt index
32405c45ca9SRussell King  *	@edges: interrupt edges to enable
32505c45ca9SRussell King  *
32605c45ca9SRussell King  *	Enable the specified interrupt to trigger on %UCB_RISING,
32705c45ca9SRussell King  *	%UCB_FALLING or both edges.  The interrupt should have been
32805c45ca9SRussell King  *	hooked by ucb1x00_hook_irq.
32905c45ca9SRussell King  */
33005c45ca9SRussell King void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
33105c45ca9SRussell King {
33205c45ca9SRussell King 	unsigned long flags;
33305c45ca9SRussell King 
33405c45ca9SRussell King 	if (idx < 16) {
33505c45ca9SRussell King 		spin_lock_irqsave(&ucb->lock, flags);
33605c45ca9SRussell King 
33705c45ca9SRussell King 		ucb1x00_enable(ucb);
33805c45ca9SRussell King 		if (edges & UCB_RISING) {
33905c45ca9SRussell King 			ucb->irq_ris_enbl |= 1 << idx;
34005c45ca9SRussell King 			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
34105c45ca9SRussell King 		}
34205c45ca9SRussell King 		if (edges & UCB_FALLING) {
34305c45ca9SRussell King 			ucb->irq_fal_enbl |= 1 << idx;
34405c45ca9SRussell King 			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
34505c45ca9SRussell King 		}
34605c45ca9SRussell King 		ucb1x00_disable(ucb);
34705c45ca9SRussell King 		spin_unlock_irqrestore(&ucb->lock, flags);
34805c45ca9SRussell King 	}
34905c45ca9SRussell King }
35005c45ca9SRussell King 
35105c45ca9SRussell King /**
35205c45ca9SRussell King  *	ucb1x00_disable_irq - disable an UCB1x00 interrupt source
35305c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
35405c45ca9SRussell King  *	@edges: interrupt edges to disable
35505c45ca9SRussell King  *
35605c45ca9SRussell King  *	Disable the specified interrupt triggering on the specified
35705c45ca9SRussell King  *	(%UCB_RISING, %UCB_FALLING or both) edges.
35805c45ca9SRussell King  */
35905c45ca9SRussell King void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
36005c45ca9SRussell King {
36105c45ca9SRussell King 	unsigned long flags;
36205c45ca9SRussell King 
36305c45ca9SRussell King 	if (idx < 16) {
36405c45ca9SRussell King 		spin_lock_irqsave(&ucb->lock, flags);
36505c45ca9SRussell King 
36605c45ca9SRussell King 		ucb1x00_enable(ucb);
36705c45ca9SRussell King 		if (edges & UCB_RISING) {
36805c45ca9SRussell King 			ucb->irq_ris_enbl &= ~(1 << idx);
36905c45ca9SRussell King 			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
37005c45ca9SRussell King 		}
37105c45ca9SRussell King 		if (edges & UCB_FALLING) {
37205c45ca9SRussell King 			ucb->irq_fal_enbl &= ~(1 << idx);
37305c45ca9SRussell King 			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
37405c45ca9SRussell King 		}
37505c45ca9SRussell King 		ucb1x00_disable(ucb);
37605c45ca9SRussell King 		spin_unlock_irqrestore(&ucb->lock, flags);
37705c45ca9SRussell King 	}
37805c45ca9SRussell King }
37905c45ca9SRussell King 
38005c45ca9SRussell King /**
38105c45ca9SRussell King  *	ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
38205c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
38305c45ca9SRussell King  *	@idx: interrupt index
38405c45ca9SRussell King  *	@devid: device id.
38505c45ca9SRussell King  *
38605c45ca9SRussell King  *	Disable the interrupt source and remove the handler.  devid must
38705c45ca9SRussell King  *	match the devid passed when hooking the interrupt.
38805c45ca9SRussell King  *
38905c45ca9SRussell King  *	Returns zero on success, or one of the following errors:
39005c45ca9SRussell King  *	 -EINVAL if the interrupt index is invalid
39105c45ca9SRussell King  *	 -ENOENT if devid does not match
39205c45ca9SRussell King  */
39305c45ca9SRussell King int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
39405c45ca9SRussell King {
39505c45ca9SRussell King 	struct ucb1x00_irq *irq;
39605c45ca9SRussell King 	int ret;
39705c45ca9SRussell King 
39805c45ca9SRussell King 	if (idx >= 16)
39905c45ca9SRussell King 		goto bad;
40005c45ca9SRussell King 
40105c45ca9SRussell King 	irq = ucb->irq_handler + idx;
40205c45ca9SRussell King 	ret = -ENOENT;
40305c45ca9SRussell King 
40405c45ca9SRussell King 	spin_lock_irq(&ucb->lock);
40505c45ca9SRussell King 	if (irq->devid == devid) {
40605c45ca9SRussell King 		ucb->irq_ris_enbl &= ~(1 << idx);
40705c45ca9SRussell King 		ucb->irq_fal_enbl &= ~(1 << idx);
40805c45ca9SRussell King 
40905c45ca9SRussell King 		ucb1x00_enable(ucb);
41005c45ca9SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
41105c45ca9SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
41205c45ca9SRussell King 		ucb1x00_disable(ucb);
41305c45ca9SRussell King 
41405c45ca9SRussell King 		irq->fn = NULL;
41505c45ca9SRussell King 		irq->devid = NULL;
41605c45ca9SRussell King 		ret = 0;
41705c45ca9SRussell King 	}
41805c45ca9SRussell King 	spin_unlock_irq(&ucb->lock);
41905c45ca9SRussell King 	return ret;
42005c45ca9SRussell King 
42105c45ca9SRussell King bad:
42205c45ca9SRussell King 	printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
42305c45ca9SRussell King 	return -EINVAL;
42405c45ca9SRussell King }
42505c45ca9SRussell King 
42605c45ca9SRussell King static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
42705c45ca9SRussell King {
42805c45ca9SRussell King 	struct ucb1x00_dev *dev;
42905c45ca9SRussell King 	int ret = -ENOMEM;
43005c45ca9SRussell King 
43105c45ca9SRussell King 	dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL);
43205c45ca9SRussell King 	if (dev) {
43305c45ca9SRussell King 		dev->ucb = ucb;
43405c45ca9SRussell King 		dev->drv = drv;
43505c45ca9SRussell King 
43605c45ca9SRussell King 		ret = drv->add(dev);
43705c45ca9SRussell King 
43805c45ca9SRussell King 		if (ret == 0) {
43905c45ca9SRussell King 			list_add(&dev->dev_node, &ucb->devs);
44005c45ca9SRussell King 			list_add(&dev->drv_node, &drv->devs);
44105c45ca9SRussell King 		} else {
44205c45ca9SRussell King 			kfree(dev);
44305c45ca9SRussell King 		}
44405c45ca9SRussell King 	}
44505c45ca9SRussell King 	return ret;
44605c45ca9SRussell King }
44705c45ca9SRussell King 
44805c45ca9SRussell King static void ucb1x00_remove_dev(struct ucb1x00_dev *dev)
44905c45ca9SRussell King {
45005c45ca9SRussell King 	dev->drv->remove(dev);
45105c45ca9SRussell King 	list_del(&dev->dev_node);
45205c45ca9SRussell King 	list_del(&dev->drv_node);
45305c45ca9SRussell King 	kfree(dev);
45405c45ca9SRussell King }
45505c45ca9SRussell King 
45605c45ca9SRussell King /*
45705c45ca9SRussell King  * Try to probe our interrupt, rather than relying on lots of
45805c45ca9SRussell King  * hard-coded machine dependencies.  For reference, the expected
45905c45ca9SRussell King  * IRQ mappings are:
46005c45ca9SRussell King  *
46105c45ca9SRussell King  *  	Machine		Default IRQ
46205c45ca9SRussell King  *	adsbitsy	IRQ_GPCIN4
46305c45ca9SRussell King  *	cerf		IRQ_GPIO_UCB1200_IRQ
46405c45ca9SRussell King  *	flexanet	IRQ_GPIO_GUI
46505c45ca9SRussell King  *	freebird	IRQ_GPIO_FREEBIRD_UCB1300_IRQ
46605c45ca9SRussell King  *	graphicsclient	ADS_EXT_IRQ(8)
46705c45ca9SRussell King  *	graphicsmaster	ADS_EXT_IRQ(8)
46805c45ca9SRussell King  *	lart		LART_IRQ_UCB1200
46905c45ca9SRussell King  *	omnimeter	IRQ_GPIO23
47005c45ca9SRussell King  *	pfs168		IRQ_GPIO_UCB1300_IRQ
47105c45ca9SRussell King  *	simpad		IRQ_GPIO_UCB1300_IRQ
47205c45ca9SRussell King  *	shannon		SHANNON_IRQ_GPIO_IRQ_CODEC
47305c45ca9SRussell King  *	yopy		IRQ_GPIO_UCB1200_IRQ
47405c45ca9SRussell King  */
47505c45ca9SRussell King static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
47605c45ca9SRussell King {
47705c45ca9SRussell King 	unsigned long mask;
47805c45ca9SRussell King 
47905c45ca9SRussell King 	mask = probe_irq_on();
480cfc73656SIngo Molnar 	if (!mask) {
481cfc73656SIngo Molnar 		probe_irq_off(mask);
48205c45ca9SRussell King 		return NO_IRQ;
483cfc73656SIngo Molnar 	}
48405c45ca9SRussell King 
48505c45ca9SRussell King 	/*
48605c45ca9SRussell King 	 * Enable the ADC interrupt.
48705c45ca9SRussell King 	 */
48805c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
48905c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
49005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
49105c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
49205c45ca9SRussell King 
49305c45ca9SRussell King 	/*
49405c45ca9SRussell King 	 * Cause an ADC interrupt.
49505c45ca9SRussell King 	 */
49605c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
49705c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
49805c45ca9SRussell King 
49905c45ca9SRussell King 	/*
50005c45ca9SRussell King 	 * Wait for the conversion to complete.
50105c45ca9SRussell King 	 */
50205c45ca9SRussell King 	while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0);
50305c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, 0);
50405c45ca9SRussell King 
50505c45ca9SRussell King 	/*
50605c45ca9SRussell King 	 * Disable and clear interrupt.
50705c45ca9SRussell King 	 */
50805c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_RIS, 0);
50905c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_FAL, 0);
51005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
51105c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
51205c45ca9SRussell King 
51305c45ca9SRussell King 	/*
51405c45ca9SRussell King 	 * Read triggered interrupt.
51505c45ca9SRussell King 	 */
51605c45ca9SRussell King 	return probe_irq_off(mask);
51705c45ca9SRussell King }
51805c45ca9SRussell King 
5190c55445fSTony Jones static void ucb1x00_release(struct device *dev)
520585f5457SNicolas Pitre {
521585f5457SNicolas Pitre 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
522585f5457SNicolas Pitre 	kfree(ucb);
523585f5457SNicolas Pitre }
524585f5457SNicolas Pitre 
525585f5457SNicolas Pitre static struct class ucb1x00_class = {
526585f5457SNicolas Pitre 	.name		= "ucb1x00",
5270c55445fSTony Jones 	.dev_release	= ucb1x00_release,
528585f5457SNicolas Pitre };
529585f5457SNicolas Pitre 
53005c45ca9SRussell King static int ucb1x00_probe(struct mcp *mcp)
53105c45ca9SRussell King {
5322f7510c6SRussell King 	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
53305c45ca9SRussell King 	struct ucb1x00_driver *drv;
5342f7510c6SRussell King 	struct ucb1x00 *ucb;
53505c45ca9SRussell King 	unsigned int id;
53605c45ca9SRussell King 	int ret = -ENODEV;
5379ca3dc80SThomas Kunze 	int temp;
53805c45ca9SRussell King 
5392f7510c6SRussell King 	/* Tell the platform to deassert the UCB1x00 reset */
5402f7510c6SRussell King 	if (pdata && pdata->reset)
5412f7510c6SRussell King 		pdata->reset(UCB_RST_PROBE);
5422f7510c6SRussell King 
54305c45ca9SRussell King 	mcp_enable(mcp);
54405c45ca9SRussell King 	id = mcp_reg_read(mcp, UCB_ID);
54505c45ca9SRussell King 
54665f2e753SRussell King 	if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
54765f2e753SRussell King 		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
54805c45ca9SRussell King 		goto err_disable;
54905c45ca9SRussell King 	}
55005c45ca9SRussell King 
551dd00cc48SYoann Padioleau 	ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
55205c45ca9SRussell King 	ret = -ENOMEM;
55305c45ca9SRussell King 	if (!ucb)
55405c45ca9SRussell King 		goto err_disable;
55505c45ca9SRussell King 
5560c55445fSTony Jones 	ucb->dev.class = &ucb1x00_class;
5570c55445fSTony Jones 	ucb->dev.parent = &mcp->attached_device;
55865f2e753SRussell King 	dev_set_name(&ucb->dev, "ucb1x00");
55905c45ca9SRussell King 
56005c45ca9SRussell King 	spin_lock_init(&ucb->lock);
56105c45ca9SRussell King 	spin_lock_init(&ucb->io_lock);
562cae15476SRussell King 	mutex_init(&ucb->adc_mutex);
56305c45ca9SRussell King 
56465f2e753SRussell King 	ucb->id  = id;
56505c45ca9SRussell King 	ucb->mcp = mcp;
56605c45ca9SRussell King 	ucb->irq = ucb1x00_detect_irq(ucb);
56705c45ca9SRussell King 	if (ucb->irq == NO_IRQ) {
56865f2e753SRussell King 		printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
56905c45ca9SRussell King 		ret = -ENODEV;
57005c45ca9SRussell King 		goto err_free;
57105c45ca9SRussell King 	}
57205c45ca9SRussell King 
5739ca3dc80SThomas Kunze 	ucb->gpio.base = -1;
574abe06082SRussell King 	if (pdata && pdata->gpio_base) {
5759ca3dc80SThomas Kunze 		ucb->gpio.label = dev_name(&ucb->dev);
576abe06082SRussell King 		ucb->gpio.base = pdata->gpio_base;
5779ca3dc80SThomas Kunze 		ucb->gpio.ngpio = 10;
5789ca3dc80SThomas Kunze 		ucb->gpio.set = ucb1x00_gpio_set;
5799ca3dc80SThomas Kunze 		ucb->gpio.get = ucb1x00_gpio_get;
5809ca3dc80SThomas Kunze 		ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
5819ca3dc80SThomas Kunze 		ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
5829ca3dc80SThomas Kunze 		ret = gpiochip_add(&ucb->gpio);
5839ca3dc80SThomas Kunze 		if (ret)
5849ca3dc80SThomas Kunze 			goto err_free;
5859ca3dc80SThomas Kunze 	} else
5869ca3dc80SThomas Kunze 		dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
5879ca3dc80SThomas Kunze 
588dace1453SThomas Gleixner 	ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
58965f2e753SRussell King 			  "UCB1x00", ucb);
59005c45ca9SRussell King 	if (ret) {
59165f2e753SRussell King 		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
59265f2e753SRussell King 			ucb->irq, ret);
5939ca3dc80SThomas Kunze 		goto err_gpio;
59405c45ca9SRussell King 	}
59505c45ca9SRussell King 
59605c45ca9SRussell King 	mcp_set_drvdata(mcp, ucb);
59705c45ca9SRussell King 
5980c55445fSTony Jones 	ret = device_register(&ucb->dev);
59905c45ca9SRussell King 	if (ret)
60005c45ca9SRussell King 		goto err_irq;
60105c45ca9SRussell King 
6029ca3dc80SThomas Kunze 
60305c45ca9SRussell King 	INIT_LIST_HEAD(&ucb->devs);
604a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
60505c45ca9SRussell King 	list_add(&ucb->node, &ucb1x00_devices);
60605c45ca9SRussell King 	list_for_each_entry(drv, &ucb1x00_drivers, node) {
60705c45ca9SRussell King 		ucb1x00_add_dev(ucb, drv);
60805c45ca9SRussell King 	}
609a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
6109ca3dc80SThomas Kunze 
6112f7510c6SRussell King 	return ret;
61205c45ca9SRussell King 
61305c45ca9SRussell King  err_irq:
61405c45ca9SRussell King 	free_irq(ucb->irq, ucb);
6159ca3dc80SThomas Kunze  err_gpio:
6169ca3dc80SThomas Kunze 	if (ucb->gpio.base != -1)
6179ca3dc80SThomas Kunze 		temp = gpiochip_remove(&ucb->gpio);
61805c45ca9SRussell King  err_free:
61905c45ca9SRussell King 	kfree(ucb);
62005c45ca9SRussell King  err_disable:
62105c45ca9SRussell King 	mcp_disable(mcp);
62205c45ca9SRussell King  out:
6232f7510c6SRussell King 	if (pdata && pdata->reset)
6242f7510c6SRussell King 		pdata->reset(UCB_RST_PROBE_FAIL);
62505c45ca9SRussell King 	return ret;
62605c45ca9SRussell King }
62705c45ca9SRussell King 
62805c45ca9SRussell King static void ucb1x00_remove(struct mcp *mcp)
62905c45ca9SRussell King {
6302f7510c6SRussell King 	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
63105c45ca9SRussell King 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
63205c45ca9SRussell King 	struct list_head *l, *n;
6339ca3dc80SThomas Kunze 	int ret;
63405c45ca9SRussell King 
635a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
63605c45ca9SRussell King 	list_del(&ucb->node);
63705c45ca9SRussell King 	list_for_each_safe(l, n, &ucb->devs) {
63805c45ca9SRussell King 		struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, dev_node);
63905c45ca9SRussell King 		ucb1x00_remove_dev(dev);
64005c45ca9SRussell King 	}
641a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
64205c45ca9SRussell King 
6439ca3dc80SThomas Kunze 	if (ucb->gpio.base != -1) {
6449ca3dc80SThomas Kunze 		ret = gpiochip_remove(&ucb->gpio);
6459ca3dc80SThomas Kunze 		if (ret)
6469ca3dc80SThomas Kunze 			dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
6479ca3dc80SThomas Kunze 	}
6489ca3dc80SThomas Kunze 
64905c45ca9SRussell King 	free_irq(ucb->irq, ucb);
6500c55445fSTony Jones 	device_unregister(&ucb->dev);
6512f7510c6SRussell King 
6522f7510c6SRussell King 	if (pdata && pdata->reset)
6532f7510c6SRussell King 		pdata->reset(UCB_RST_REMOVE);
65405c45ca9SRussell King }
65505c45ca9SRussell King 
65605c45ca9SRussell King int ucb1x00_register_driver(struct ucb1x00_driver *drv)
65705c45ca9SRussell King {
65805c45ca9SRussell King 	struct ucb1x00 *ucb;
65905c45ca9SRussell King 
66005c45ca9SRussell King 	INIT_LIST_HEAD(&drv->devs);
661a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
66205c45ca9SRussell King 	list_add(&drv->node, &ucb1x00_drivers);
66305c45ca9SRussell King 	list_for_each_entry(ucb, &ucb1x00_devices, node) {
66405c45ca9SRussell King 		ucb1x00_add_dev(ucb, drv);
66505c45ca9SRussell King 	}
666a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
66705c45ca9SRussell King 	return 0;
66805c45ca9SRussell King }
66905c45ca9SRussell King 
67005c45ca9SRussell King void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
67105c45ca9SRussell King {
67205c45ca9SRussell King 	struct list_head *n, *l;
67305c45ca9SRussell King 
674a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
67505c45ca9SRussell King 	list_del(&drv->node);
67605c45ca9SRussell King 	list_for_each_safe(l, n, &drv->devs) {
67705c45ca9SRussell King 		struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, drv_node);
67805c45ca9SRussell King 		ucb1x00_remove_dev(dev);
67905c45ca9SRussell King 	}
680a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
68105c45ca9SRussell King }
68205c45ca9SRussell King 
68305c45ca9SRussell King static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state)
68405c45ca9SRussell King {
68505c45ca9SRussell King 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
68605c45ca9SRussell King 	struct ucb1x00_dev *dev;
68705c45ca9SRussell King 
688a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
68905c45ca9SRussell King 	list_for_each_entry(dev, &ucb->devs, dev_node) {
69005c45ca9SRussell King 		if (dev->drv->suspend)
69105c45ca9SRussell King 			dev->drv->suspend(dev, state);
69205c45ca9SRussell King 	}
693a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
69405c45ca9SRussell King 	return 0;
69505c45ca9SRussell King }
69605c45ca9SRussell King 
69705c45ca9SRussell King static int ucb1x00_resume(struct mcp *mcp)
69805c45ca9SRussell King {
69905c45ca9SRussell King 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
70005c45ca9SRussell King 	struct ucb1x00_dev *dev;
70105c45ca9SRussell King 
7022e95e51eSRussell King 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
7039ca3dc80SThomas Kunze 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
704a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
70505c45ca9SRussell King 	list_for_each_entry(dev, &ucb->devs, dev_node) {
70605c45ca9SRussell King 		if (dev->drv->resume)
70705c45ca9SRussell King 			dev->drv->resume(dev);
70805c45ca9SRussell King 	}
709a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
71005c45ca9SRussell King 	return 0;
71105c45ca9SRussell King }
71205c45ca9SRussell King 
71305c45ca9SRussell King static struct mcp_driver ucb1x00_driver = {
71405c45ca9SRussell King 	.drv		= {
71505c45ca9SRussell King 		.name	= "ucb1x00",
716ddb1e04aSRussell King 		.owner	= THIS_MODULE,
71705c45ca9SRussell King 	},
71805c45ca9SRussell King 	.probe		= ucb1x00_probe,
71905c45ca9SRussell King 	.remove		= ucb1x00_remove,
72005c45ca9SRussell King 	.suspend	= ucb1x00_suspend,
72105c45ca9SRussell King 	.resume		= ucb1x00_resume,
72205c45ca9SRussell King };
72305c45ca9SRussell King 
72405c45ca9SRussell King static int __init ucb1x00_init(void)
72505c45ca9SRussell King {
72605c45ca9SRussell King 	int ret = class_register(&ucb1x00_class);
72705c45ca9SRussell King 	if (ret == 0) {
72805c45ca9SRussell King 		ret = mcp_driver_register(&ucb1x00_driver);
72905c45ca9SRussell King 		if (ret)
73005c45ca9SRussell King 			class_unregister(&ucb1x00_class);
73105c45ca9SRussell King 	}
73205c45ca9SRussell King 	return ret;
73305c45ca9SRussell King }
73405c45ca9SRussell King 
73505c45ca9SRussell King static void __exit ucb1x00_exit(void)
73605c45ca9SRussell King {
73705c45ca9SRussell King 	mcp_driver_unregister(&ucb1x00_driver);
73805c45ca9SRussell King 	class_unregister(&ucb1x00_class);
73905c45ca9SRussell King }
74005c45ca9SRussell King 
74105c45ca9SRussell King module_init(ucb1x00_init);
74205c45ca9SRussell King module_exit(ucb1x00_exit);
74305c45ca9SRussell King 
74405c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_set_dir);
74505c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_write);
74605c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_read);
74705c45ca9SRussell King 
74805c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_enable);
74905c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_read);
75005c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_disable);
75105c45ca9SRussell King 
75205c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_hook_irq);
75305c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_free_irq);
75405c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_enable_irq);
75505c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_disable_irq);
75605c45ca9SRussell King 
75705c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_register_driver);
75805c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_unregister_driver);
75905c45ca9SRussell King 
760ddb1e04aSRussell King MODULE_ALIAS("mcp:ucb1x00");
76105c45ca9SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
76205c45ca9SRussell King MODULE_DESCRIPTION("UCB1x00 core driver");
76305c45ca9SRussell King MODULE_LICENSE("GPL");
764