xref: /openbmc/linux/drivers/mfd/ucb1x00-core.c (revision 03bf96cf)
184a14ae8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
205c45ca9SRussell King /*
305c45ca9SRussell King  *  linux/drivers/mfd/ucb1x00-core.c
405c45ca9SRussell King  *
505c45ca9SRussell King  *  Copyright (C) 2001 Russell King, All Rights Reserved.
605c45ca9SRussell King  *
705c45ca9SRussell King  *  The UCB1x00 core driver provides basic services for handling IO,
805c45ca9SRussell King  *  the ADC, interrupts, and accessing registers.  It is designed
905c45ca9SRussell King  *  such that everything goes through this layer, thereby providing
1005c45ca9SRussell King  *  a consistent locking methodology, as well as allowing the drivers
1105c45ca9SRussell King  *  to be used on other non-MCP-enabled hardware platforms.
1205c45ca9SRussell King  *
1305c45ca9SRussell King  *  Note that all locks are private to this file.  Nothing else may
1405c45ca9SRussell King  *  touch them.
1505c45ca9SRussell King  */
1605c45ca9SRussell King #include <linux/module.h>
1705c45ca9SRussell King #include <linux/kernel.h>
18d43c36dcSAlexey Dobriyan #include <linux/sched.h>
1905c45ca9SRussell King #include <linux/slab.h>
2005c45ca9SRussell King #include <linux/init.h>
2105c45ca9SRussell King #include <linux/errno.h>
2205c45ca9SRussell King #include <linux/interrupt.h>
23a3364409SRussell King #include <linux/irq.h>
2405c45ca9SRussell King #include <linux/device.h>
25a621aaedSArjan van de Ven #include <linux/mutex.h>
26c8602edfSThomas Kunze #include <linux/mfd/ucb1x00.h>
275a09b712SRussell King #include <linux/pm.h>
287d94352eSLinus Walleij #include <linux/gpio/driver.h>
2905c45ca9SRussell King 
30a621aaedSArjan van de Ven static DEFINE_MUTEX(ucb1x00_mutex);
3105c45ca9SRussell King static LIST_HEAD(ucb1x00_drivers);
3205c45ca9SRussell King static LIST_HEAD(ucb1x00_devices);
3305c45ca9SRussell King 
3405c45ca9SRussell King /**
3505c45ca9SRussell King  *	ucb1x00_io_set_dir - set IO direction
3605c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
3705c45ca9SRussell King  *	@in:  bitfield of IO pins to be set as inputs
3805c45ca9SRussell King  *	@out: bitfield of IO pins to be set as outputs
3905c45ca9SRussell King  *
4005c45ca9SRussell King  *	Set the IO direction of the ten general purpose IO pins on
4105c45ca9SRussell King  *	the UCB1x00 chip.  The @in bitfield has priority over the
4205c45ca9SRussell King  *	@out bitfield, in that if you specify a pin as both input
4305c45ca9SRussell King  *	and output, it will end up as an input.
4405c45ca9SRussell King  *
4505c45ca9SRussell King  *	ucb1x00_enable must have been called to enable the comms
4605c45ca9SRussell King  *	before using this function.
4705c45ca9SRussell King  *
4805c45ca9SRussell King  *	This function takes a spinlock, disabling interrupts.
4905c45ca9SRussell King  */
ucb1x00_io_set_dir(struct ucb1x00 * ucb,unsigned int in,unsigned int out)5005c45ca9SRussell King void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out)
5105c45ca9SRussell King {
5205c45ca9SRussell King 	unsigned long flags;
5305c45ca9SRussell King 
5405c45ca9SRussell King 	spin_lock_irqsave(&ucb->io_lock, flags);
5505c45ca9SRussell King 	ucb->io_dir |= out;
5605c45ca9SRussell King 	ucb->io_dir &= ~in;
5705c45ca9SRussell King 
5805c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
5905c45ca9SRussell King 	spin_unlock_irqrestore(&ucb->io_lock, flags);
6005c45ca9SRussell King }
6105c45ca9SRussell King 
6205c45ca9SRussell King /**
6305c45ca9SRussell King  *	ucb1x00_io_write - set or clear IO outputs
6405c45ca9SRussell King  *	@ucb:   UCB1x00 structure describing chip
6505c45ca9SRussell King  *	@set:   bitfield of IO pins to set to logic '1'
6605c45ca9SRussell King  *	@clear: bitfield of IO pins to set to logic '0'
6705c45ca9SRussell King  *
6805c45ca9SRussell King  *	Set the IO output state of the specified IO pins.  The value
6905c45ca9SRussell King  *	is retained if the pins are subsequently configured as inputs.
7005c45ca9SRussell King  *	The @clear bitfield has priority over the @set bitfield -
7105c45ca9SRussell King  *	outputs will be cleared.
7205c45ca9SRussell King  *
7305c45ca9SRussell King  *	ucb1x00_enable must have been called to enable the comms
7405c45ca9SRussell King  *	before using this function.
7505c45ca9SRussell King  *
7605c45ca9SRussell King  *	This function takes a spinlock, disabling interrupts.
7705c45ca9SRussell King  */
ucb1x00_io_write(struct ucb1x00 * ucb,unsigned int set,unsigned int clear)7805c45ca9SRussell King void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
7905c45ca9SRussell King {
8005c45ca9SRussell King 	unsigned long flags;
8105c45ca9SRussell King 
8205c45ca9SRussell King 	spin_lock_irqsave(&ucb->io_lock, flags);
8305c45ca9SRussell King 	ucb->io_out |= set;
8405c45ca9SRussell King 	ucb->io_out &= ~clear;
8505c45ca9SRussell King 
8605c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
8705c45ca9SRussell King 	spin_unlock_irqrestore(&ucb->io_lock, flags);
8805c45ca9SRussell King }
8905c45ca9SRussell King 
9005c45ca9SRussell King /**
9105c45ca9SRussell King  *	ucb1x00_io_read - read the current state of the IO pins
9205c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
9305c45ca9SRussell King  *
9405c45ca9SRussell King  *	Return a bitfield describing the logic state of the ten
9505c45ca9SRussell King  *	general purpose IO pins.
9605c45ca9SRussell King  *
9705c45ca9SRussell King  *	ucb1x00_enable must have been called to enable the comms
9805c45ca9SRussell King  *	before using this function.
9905c45ca9SRussell King  *
100cae15476SRussell King  *	This function does not take any mutexes or spinlocks.
10105c45ca9SRussell King  */
ucb1x00_io_read(struct ucb1x00 * ucb)10205c45ca9SRussell King unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
10305c45ca9SRussell King {
10405c45ca9SRussell King 	return ucb1x00_reg_read(ucb, UCB_IO_DATA);
10505c45ca9SRussell King }
10605c45ca9SRussell King 
ucb1x00_gpio_set(struct gpio_chip * chip,unsigned offset,int value)1079ca3dc80SThomas Kunze static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
1089ca3dc80SThomas Kunze {
1097d94352eSLinus Walleij 	struct ucb1x00 *ucb = gpiochip_get_data(chip);
1109ca3dc80SThomas Kunze 	unsigned long flags;
1119ca3dc80SThomas Kunze 
1129ca3dc80SThomas Kunze 	spin_lock_irqsave(&ucb->io_lock, flags);
1139ca3dc80SThomas Kunze 	if (value)
1149ca3dc80SThomas Kunze 		ucb->io_out |= 1 << offset;
1159ca3dc80SThomas Kunze 	else
1169ca3dc80SThomas Kunze 		ucb->io_out &= ~(1 << offset);
1179ca3dc80SThomas Kunze 
118ed442b67SRussell King 	ucb1x00_enable(ucb);
1199ca3dc80SThomas Kunze 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
120ed442b67SRussell King 	ucb1x00_disable(ucb);
1219ca3dc80SThomas Kunze 	spin_unlock_irqrestore(&ucb->io_lock, flags);
1229ca3dc80SThomas Kunze }
1239ca3dc80SThomas Kunze 
ucb1x00_gpio_get(struct gpio_chip * chip,unsigned offset)1249ca3dc80SThomas Kunze static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
1259ca3dc80SThomas Kunze {
1267d94352eSLinus Walleij 	struct ucb1x00 *ucb = gpiochip_get_data(chip);
127ed442b67SRussell King 	unsigned val;
128ed442b67SRussell King 
129ed442b67SRussell King 	ucb1x00_enable(ucb);
130ed442b67SRussell King 	val = ucb1x00_reg_read(ucb, UCB_IO_DATA);
131ed442b67SRussell King 	ucb1x00_disable(ucb);
132ed442b67SRussell King 
1330c7f3f92SLinus Walleij 	return !!(val & (1 << offset));
1349ca3dc80SThomas Kunze }
1359ca3dc80SThomas Kunze 
ucb1x00_gpio_direction_input(struct gpio_chip * chip,unsigned offset)1369ca3dc80SThomas Kunze static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
1379ca3dc80SThomas Kunze {
1387d94352eSLinus Walleij 	struct ucb1x00 *ucb = gpiochip_get_data(chip);
1399ca3dc80SThomas Kunze 	unsigned long flags;
1409ca3dc80SThomas Kunze 
1419ca3dc80SThomas Kunze 	spin_lock_irqsave(&ucb->io_lock, flags);
1429ca3dc80SThomas Kunze 	ucb->io_dir &= ~(1 << offset);
143ed442b67SRussell King 	ucb1x00_enable(ucb);
1449ca3dc80SThomas Kunze 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
145ed442b67SRussell King 	ucb1x00_disable(ucb);
1469ca3dc80SThomas Kunze 	spin_unlock_irqrestore(&ucb->io_lock, flags);
1479ca3dc80SThomas Kunze 
1489ca3dc80SThomas Kunze 	return 0;
1499ca3dc80SThomas Kunze }
1509ca3dc80SThomas Kunze 
ucb1x00_gpio_direction_output(struct gpio_chip * chip,unsigned offset,int value)1519ca3dc80SThomas Kunze static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
1529ca3dc80SThomas Kunze 		, int value)
1539ca3dc80SThomas Kunze {
1547d94352eSLinus Walleij 	struct ucb1x00 *ucb = gpiochip_get_data(chip);
1559ca3dc80SThomas Kunze 	unsigned long flags;
156c23bb602SRussell King 	unsigned old, mask = 1 << offset;
1579ca3dc80SThomas Kunze 
1589ca3dc80SThomas Kunze 	spin_lock_irqsave(&ucb->io_lock, flags);
159c23bb602SRussell King 	old = ucb->io_out;
1609ca3dc80SThomas Kunze 	if (value)
161c23bb602SRussell King 		ucb->io_out |= mask;
1629ca3dc80SThomas Kunze 	else
163c23bb602SRussell King 		ucb->io_out &= ~mask;
164c23bb602SRussell King 
165ed442b67SRussell King 	ucb1x00_enable(ucb);
166c23bb602SRussell King 	if (old != ucb->io_out)
1679ca3dc80SThomas Kunze 		ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
168c23bb602SRussell King 
169c23bb602SRussell King 	if (!(ucb->io_dir & mask)) {
170c23bb602SRussell King 		ucb->io_dir |= mask;
171c23bb602SRussell King 		ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
172c23bb602SRussell King 	}
173ed442b67SRussell King 	ucb1x00_disable(ucb);
1749ca3dc80SThomas Kunze 	spin_unlock_irqrestore(&ucb->io_lock, flags);
1759ca3dc80SThomas Kunze 
1769ca3dc80SThomas Kunze 	return 0;
1779ca3dc80SThomas Kunze }
1789ca3dc80SThomas Kunze 
ucb1x00_to_irq(struct gpio_chip * chip,unsigned offset)179a3364409SRussell King static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset)
180a3364409SRussell King {
1817d94352eSLinus Walleij 	struct ucb1x00 *ucb = gpiochip_get_data(chip);
182a3364409SRussell King 
183a3364409SRussell King 	return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO;
184a3364409SRussell King }
185a3364409SRussell King 
18605c45ca9SRussell King /*
18705c45ca9SRussell King  * UCB1300 data sheet says we must:
18805c45ca9SRussell King  *  1. enable ADC	=> 5us (including reference startup time)
18905c45ca9SRussell King  *  2. select input	=> 51*tsibclk  => 4.3us
19005c45ca9SRussell King  *  3. start conversion	=> 102*tsibclk => 8.5us
19105c45ca9SRussell King  * (tsibclk = 1/11981000)
19205c45ca9SRussell King  * Period between SIB 128-bit frames = 10.7us
19305c45ca9SRussell King  */
19405c45ca9SRussell King 
19505c45ca9SRussell King /**
19605c45ca9SRussell King  *	ucb1x00_adc_enable - enable the ADC converter
19705c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
19805c45ca9SRussell King  *
19905c45ca9SRussell King  *	Enable the ucb1x00 and ADC converter on the UCB1x00 for use.
20005c45ca9SRussell King  *	Any code wishing to use the ADC converter must call this
20105c45ca9SRussell King  *	function prior to using it.
20205c45ca9SRussell King  *
203cae15476SRussell King  *	This function takes the ADC mutex to prevent two or more
20405c45ca9SRussell King  *	concurrent uses, and therefore may sleep.  As a result, it
20505c45ca9SRussell King  *	can only be called from process context, not interrupt
20605c45ca9SRussell King  *	context.
20705c45ca9SRussell King  *
20805c45ca9SRussell King  *	You should release the ADC as soon as possible using
20905c45ca9SRussell King  *	ucb1x00_adc_disable.
21005c45ca9SRussell King  */
ucb1x00_adc_enable(struct ucb1x00 * ucb)21105c45ca9SRussell King void ucb1x00_adc_enable(struct ucb1x00 *ucb)
21205c45ca9SRussell King {
213cae15476SRussell King 	mutex_lock(&ucb->adc_mutex);
21405c45ca9SRussell King 
21505c45ca9SRussell King 	ucb->adc_cr |= UCB_ADC_ENA;
21605c45ca9SRussell King 
21705c45ca9SRussell King 	ucb1x00_enable(ucb);
21805c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
21905c45ca9SRussell King }
22005c45ca9SRussell King 
22105c45ca9SRussell King /**
22205c45ca9SRussell King  *	ucb1x00_adc_read - read the specified ADC channel
22305c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
22405c45ca9SRussell King  *	@adc_channel: ADC channel mask
22505c45ca9SRussell King  *	@sync: wait for syncronisation pulse.
22605c45ca9SRussell King  *
22705c45ca9SRussell King  *	Start an ADC conversion and wait for the result.  Note that
22805c45ca9SRussell King  *	synchronised ADC conversions (via the ADCSYNC pin) must wait
22905c45ca9SRussell King  *	until the trigger is asserted and the conversion is finished.
23005c45ca9SRussell King  *
23105c45ca9SRussell King  *	This function currently spins waiting for the conversion to
23205c45ca9SRussell King  *	complete (2 frames max without sync).
23305c45ca9SRussell King  *
23405c45ca9SRussell King  *	If called for a synchronised ADC conversion, it may sleep
235cae15476SRussell King  *	with the ADC mutex held.
23605c45ca9SRussell King  */
ucb1x00_adc_read(struct ucb1x00 * ucb,int adc_channel,int sync)23705c45ca9SRussell King unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
23805c45ca9SRussell King {
23905c45ca9SRussell King 	unsigned int val;
24005c45ca9SRussell King 
24105c45ca9SRussell King 	if (sync)
24205c45ca9SRussell King 		adc_channel |= UCB_ADC_SYNC_ENA;
24305c45ca9SRussell King 
24405c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel);
24505c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
24605c45ca9SRussell King 
24705c45ca9SRussell King 	for (;;) {
24805c45ca9SRussell King 		val = ucb1x00_reg_read(ucb, UCB_ADC_DATA);
24905c45ca9SRussell King 		if (val & UCB_ADC_DAT_VAL)
25005c45ca9SRussell King 			break;
25105c45ca9SRussell King 		/* yield to other processes */
25205c45ca9SRussell King 		set_current_state(TASK_INTERRUPTIBLE);
25305c45ca9SRussell King 		schedule_timeout(1);
25405c45ca9SRussell King 	}
25505c45ca9SRussell King 
25605c45ca9SRussell King 	return UCB_ADC_DAT(val);
25705c45ca9SRussell King }
25805c45ca9SRussell King 
25905c45ca9SRussell King /**
26005c45ca9SRussell King  *	ucb1x00_adc_disable - disable the ADC converter
26105c45ca9SRussell King  *	@ucb: UCB1x00 structure describing chip
26205c45ca9SRussell King  *
263cae15476SRussell King  *	Disable the ADC converter and release the ADC mutex.
26405c45ca9SRussell King  */
ucb1x00_adc_disable(struct ucb1x00 * ucb)26505c45ca9SRussell King void ucb1x00_adc_disable(struct ucb1x00 *ucb)
26605c45ca9SRussell King {
26705c45ca9SRussell King 	ucb->adc_cr &= ~UCB_ADC_ENA;
26805c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
26905c45ca9SRussell King 	ucb1x00_disable(ucb);
27005c45ca9SRussell King 
271cae15476SRussell King 	mutex_unlock(&ucb->adc_mutex);
27205c45ca9SRussell King }
27305c45ca9SRussell King 
27405c45ca9SRussell King /*
27505c45ca9SRussell King  * UCB1x00 Interrupt handling.
27605c45ca9SRussell King  *
27705c45ca9SRussell King  * The UCB1x00 can generate interrupts when the SIBCLK is stopped.
27805c45ca9SRussell King  * Since we need to read an internal register, we must re-enable
27905c45ca9SRussell King  * SIBCLK to talk to the chip.  We leave the clock running until
28005c45ca9SRussell King  * we have finished processing all interrupts from the chip.
28105c45ca9SRussell King  */
ucb1x00_irq(struct irq_desc * desc)282bd0b9ac4SThomas Gleixner static void ucb1x00_irq(struct irq_desc *desc)
28305c45ca9SRussell King {
284a3364409SRussell King 	struct ucb1x00 *ucb = irq_desc_get_handler_data(desc);
28505c45ca9SRussell King 	unsigned int isr, i;
28605c45ca9SRussell King 
28705c45ca9SRussell King 	ucb1x00_enable(ucb);
28805c45ca9SRussell King 	isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
28905c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
29005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
29105c45ca9SRussell King 
2920d674d93SThomas Gleixner 	for (i = 0; i < 16 && isr; i++, isr >>= 1)
293a3364409SRussell King 		if (isr & 1)
294a3364409SRussell King 			generic_handle_irq(ucb->irq_base + i);
29505c45ca9SRussell King 	ucb1x00_disable(ucb);
29605c45ca9SRussell King }
29705c45ca9SRussell King 
ucb1x00_irq_update(struct ucb1x00 * ucb,unsigned mask)298a3364409SRussell King static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask)
29905c45ca9SRussell King {
30005c45ca9SRussell King 	ucb1x00_enable(ucb);
301a3364409SRussell King 	if (ucb->irq_ris_enbl & mask)
302a3364409SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
303a3364409SRussell King 				  ucb->irq_mask);
304a3364409SRussell King 	if (ucb->irq_fal_enbl & mask)
305a3364409SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
306a3364409SRussell King 				  ucb->irq_mask);
30705c45ca9SRussell King 	ucb1x00_disable(ucb);
30805c45ca9SRussell King }
30905c45ca9SRussell King 
ucb1x00_irq_noop(struct irq_data * data)310a3364409SRussell King static void ucb1x00_irq_noop(struct irq_data *data)
31105c45ca9SRussell King {
31205c45ca9SRussell King }
31305c45ca9SRussell King 
ucb1x00_irq_mask(struct irq_data * data)314a3364409SRussell King static void ucb1x00_irq_mask(struct irq_data *data)
31505c45ca9SRussell King {
316a3364409SRussell King 	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
317a3364409SRussell King 	unsigned mask = 1 << (data->irq - ucb->irq_base);
31805c45ca9SRussell King 
319a3364409SRussell King 	raw_spin_lock(&ucb->irq_lock);
320a3364409SRussell King 	ucb->irq_mask &= ~mask;
321a3364409SRussell King 	ucb1x00_irq_update(ucb, mask);
322a3364409SRussell King 	raw_spin_unlock(&ucb->irq_lock);
32305c45ca9SRussell King }
32405c45ca9SRussell King 
ucb1x00_irq_unmask(struct irq_data * data)325a3364409SRussell King static void ucb1x00_irq_unmask(struct irq_data *data)
326a3364409SRussell King {
327a3364409SRussell King 	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
328a3364409SRussell King 	unsigned mask = 1 << (data->irq - ucb->irq_base);
329a3364409SRussell King 
330a3364409SRussell King 	raw_spin_lock(&ucb->irq_lock);
331a3364409SRussell King 	ucb->irq_mask |= mask;
332a3364409SRussell King 	ucb1x00_irq_update(ucb, mask);
333a3364409SRussell King 	raw_spin_unlock(&ucb->irq_lock);
33405c45ca9SRussell King }
33505c45ca9SRussell King 
ucb1x00_irq_set_type(struct irq_data * data,unsigned int type)336a3364409SRussell King static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
337a3364409SRussell King {
338a3364409SRussell King 	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
339a3364409SRussell King 	unsigned mask = 1 << (data->irq - ucb->irq_base);
340a3364409SRussell King 
341a3364409SRussell King 	raw_spin_lock(&ucb->irq_lock);
342a3364409SRussell King 	if (type & IRQ_TYPE_EDGE_RISING)
343a3364409SRussell King 		ucb->irq_ris_enbl |= mask;
344a3364409SRussell King 	else
345a3364409SRussell King 		ucb->irq_ris_enbl &= ~mask;
346a3364409SRussell King 
347a3364409SRussell King 	if (type & IRQ_TYPE_EDGE_FALLING)
348a3364409SRussell King 		ucb->irq_fal_enbl |= mask;
349a3364409SRussell King 	else
350a3364409SRussell King 		ucb->irq_fal_enbl &= ~mask;
351a3364409SRussell King 	if (ucb->irq_mask & mask) {
352a3364409SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
353a3364409SRussell King 				  ucb->irq_mask);
354a3364409SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
355a3364409SRussell King 				  ucb->irq_mask);
356a3364409SRussell King 	}
357a3364409SRussell King 	raw_spin_unlock(&ucb->irq_lock);
358a3364409SRussell King 
359a3364409SRussell King 	return 0;
360a3364409SRussell King }
361a3364409SRussell King 
ucb1x00_irq_set_wake(struct irq_data * data,unsigned int on)36233237616SRussell King static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on)
36333237616SRussell King {
36433237616SRussell King 	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
36533237616SRussell King 	struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data;
36633237616SRussell King 	unsigned mask = 1 << (data->irq - ucb->irq_base);
36733237616SRussell King 
36833237616SRussell King 	if (!pdata || !pdata->can_wakeup)
36933237616SRussell King 		return -EINVAL;
37033237616SRussell King 
37133237616SRussell King 	raw_spin_lock(&ucb->irq_lock);
37233237616SRussell King 	if (on)
37333237616SRussell King 		ucb->irq_wake |= mask;
37433237616SRussell King 	else
37533237616SRussell King 		ucb->irq_wake &= ~mask;
37633237616SRussell King 	raw_spin_unlock(&ucb->irq_lock);
37733237616SRussell King 
37833237616SRussell King 	return 0;
37933237616SRussell King }
38033237616SRussell King 
381a3364409SRussell King static struct irq_chip ucb1x00_irqchip = {
382a3364409SRussell King 	.name = "ucb1x00",
383a3364409SRussell King 	.irq_ack = ucb1x00_irq_noop,
384a3364409SRussell King 	.irq_mask = ucb1x00_irq_mask,
385a3364409SRussell King 	.irq_unmask = ucb1x00_irq_unmask,
386a3364409SRussell King 	.irq_set_type = ucb1x00_irq_set_type,
38733237616SRussell King 	.irq_set_wake = ucb1x00_irq_set_wake,
388a3364409SRussell King };
389a3364409SRussell King 
ucb1x00_add_dev(struct ucb1x00 * ucb,struct ucb1x00_driver * drv)39005c45ca9SRussell King static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
39105c45ca9SRussell King {
39205c45ca9SRussell King 	struct ucb1x00_dev *dev;
39302a0bf6eSLee Jones 	int ret;
39405c45ca9SRussell King 
39505c45ca9SRussell King 	dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL);
39602a0bf6eSLee Jones 	if (!dev)
39702a0bf6eSLee Jones 		return -ENOMEM;
39802a0bf6eSLee Jones 
39905c45ca9SRussell King 	dev->ucb = ucb;
40005c45ca9SRussell King 	dev->drv = drv;
40105c45ca9SRussell King 
40205c45ca9SRussell King 	ret = drv->add(dev);
40302a0bf6eSLee Jones 	if (ret) {
40402a0bf6eSLee Jones 		kfree(dev);
40502a0bf6eSLee Jones 		return ret;
40602a0bf6eSLee Jones 	}
40705c45ca9SRussell King 
40865b539bbSRussell King 	list_add_tail(&dev->dev_node, &ucb->devs);
40965b539bbSRussell King 	list_add_tail(&dev->drv_node, &drv->devs);
41002a0bf6eSLee Jones 
41105c45ca9SRussell King 	return ret;
41205c45ca9SRussell King }
41305c45ca9SRussell King 
ucb1x00_remove_dev(struct ucb1x00_dev * dev)41405c45ca9SRussell King static void ucb1x00_remove_dev(struct ucb1x00_dev *dev)
41505c45ca9SRussell King {
41605c45ca9SRussell King 	dev->drv->remove(dev);
41705c45ca9SRussell King 	list_del(&dev->dev_node);
41805c45ca9SRussell King 	list_del(&dev->drv_node);
41905c45ca9SRussell King 	kfree(dev);
42005c45ca9SRussell King }
42105c45ca9SRussell King 
42205c45ca9SRussell King /*
42305c45ca9SRussell King  * Try to probe our interrupt, rather than relying on lots of
42405c45ca9SRussell King  * hard-coded machine dependencies.  For reference, the expected
42505c45ca9SRussell King  * IRQ mappings are:
42605c45ca9SRussell King  *
42705c45ca9SRussell King  *  	Machine		Default IRQ
42805c45ca9SRussell King  *	adsbitsy	IRQ_GPCIN4
42905c45ca9SRussell King  *	cerf		IRQ_GPIO_UCB1200_IRQ
43005c45ca9SRussell King  *	flexanet	IRQ_GPIO_GUI
43105c45ca9SRussell King  *	freebird	IRQ_GPIO_FREEBIRD_UCB1300_IRQ
43205c45ca9SRussell King  *	graphicsclient	ADS_EXT_IRQ(8)
43305c45ca9SRussell King  *	graphicsmaster	ADS_EXT_IRQ(8)
43405c45ca9SRussell King  *	lart		LART_IRQ_UCB1200
43505c45ca9SRussell King  *	omnimeter	IRQ_GPIO23
43605c45ca9SRussell King  *	pfs168		IRQ_GPIO_UCB1300_IRQ
43705c45ca9SRussell King  *	simpad		IRQ_GPIO_UCB1300_IRQ
43805c45ca9SRussell King  *	shannon		SHANNON_IRQ_GPIO_IRQ_CODEC
43905c45ca9SRussell King  *	yopy		IRQ_GPIO_UCB1200_IRQ
44005c45ca9SRussell King  */
ucb1x00_detect_irq(struct ucb1x00 * ucb)44105c45ca9SRussell King static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
44205c45ca9SRussell King {
44305c45ca9SRussell King 	unsigned long mask;
44405c45ca9SRussell King 
44505c45ca9SRussell King 	mask = probe_irq_on();
44605c45ca9SRussell King 
44705c45ca9SRussell King 	/*
44805c45ca9SRussell King 	 * Enable the ADC interrupt.
44905c45ca9SRussell King 	 */
45005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
45105c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
45205c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
45305c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
45405c45ca9SRussell King 
45505c45ca9SRussell King 	/*
45605c45ca9SRussell King 	 * Cause an ADC interrupt.
45705c45ca9SRussell King 	 */
45805c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
45905c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
46005c45ca9SRussell King 
46105c45ca9SRussell King 	/*
46205c45ca9SRussell King 	 * Wait for the conversion to complete.
46305c45ca9SRussell King 	 */
46405c45ca9SRussell King 	while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0);
46505c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_ADC_CR, 0);
46605c45ca9SRussell King 
46705c45ca9SRussell King 	/*
46805c45ca9SRussell King 	 * Disable and clear interrupt.
46905c45ca9SRussell King 	 */
47005c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_RIS, 0);
47105c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_FAL, 0);
47205c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
47305c45ca9SRussell King 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
47405c45ca9SRussell King 
47505c45ca9SRussell King 	/*
47605c45ca9SRussell King 	 * Read triggered interrupt.
47705c45ca9SRussell King 	 */
47805c45ca9SRussell King 	return probe_irq_off(mask);
47905c45ca9SRussell King }
48005c45ca9SRussell King 
ucb1x00_release(struct device * dev)4810c55445fSTony Jones static void ucb1x00_release(struct device *dev)
482585f5457SNicolas Pitre {
483585f5457SNicolas Pitre 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
484585f5457SNicolas Pitre 	kfree(ucb);
485585f5457SNicolas Pitre }
486585f5457SNicolas Pitre 
487585f5457SNicolas Pitre static struct class ucb1x00_class = {
488585f5457SNicolas Pitre 	.name		= "ucb1x00",
4890c55445fSTony Jones 	.dev_release	= ucb1x00_release,
490585f5457SNicolas Pitre };
491585f5457SNicolas Pitre 
ucb1x00_probe(struct mcp * mcp)49205c45ca9SRussell King static int ucb1x00_probe(struct mcp *mcp)
49305c45ca9SRussell King {
4942f7510c6SRussell King 	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
49505c45ca9SRussell King 	struct ucb1x00_driver *drv;
4962f7510c6SRussell King 	struct ucb1x00 *ucb;
497a3364409SRussell King 	unsigned id, i, irq_base;
49805c45ca9SRussell King 	int ret = -ENODEV;
49905c45ca9SRussell King 
5002f7510c6SRussell King 	/* Tell the platform to deassert the UCB1x00 reset */
5012f7510c6SRussell King 	if (pdata && pdata->reset)
5022f7510c6SRussell King 		pdata->reset(UCB_RST_PROBE);
5032f7510c6SRussell King 
50405c45ca9SRussell King 	mcp_enable(mcp);
50505c45ca9SRussell King 	id = mcp_reg_read(mcp, UCB_ID);
5062b4d9d2bSRussell King 	mcp_disable(mcp);
50705c45ca9SRussell King 
50865f2e753SRussell King 	if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
50965f2e753SRussell King 		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
5102b4d9d2bSRussell King 		goto out;
51105c45ca9SRussell King 	}
51205c45ca9SRussell King 
513dd00cc48SYoann Padioleau 	ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
51405c45ca9SRussell King 	ret = -ENOMEM;
51505c45ca9SRussell King 	if (!ucb)
5162b4d9d2bSRussell King 		goto out;
51705c45ca9SRussell King 
518f5ae587fSRussell King 	device_initialize(&ucb->dev);
5190c55445fSTony Jones 	ucb->dev.class = &ucb1x00_class;
5200c55445fSTony Jones 	ucb->dev.parent = &mcp->attached_device;
52165f2e753SRussell King 	dev_set_name(&ucb->dev, "ucb1x00");
52205c45ca9SRussell King 
523a3364409SRussell King 	raw_spin_lock_init(&ucb->irq_lock);
52405c45ca9SRussell King 	spin_lock_init(&ucb->io_lock);
525cae15476SRussell King 	mutex_init(&ucb->adc_mutex);
52605c45ca9SRussell King 
52765f2e753SRussell King 	ucb->id  = id;
52805c45ca9SRussell King 	ucb->mcp = mcp;
529f5ae587fSRussell King 
530f5ae587fSRussell King 	ret = device_add(&ucb->dev);
531f5ae587fSRussell King 	if (ret)
532f5ae587fSRussell King 		goto err_dev_add;
533f5ae587fSRussell King 
5342b4d9d2bSRussell King 	ucb1x00_enable(ucb);
53505c45ca9SRussell King 	ucb->irq = ucb1x00_detect_irq(ucb);
5362b4d9d2bSRussell King 	ucb1x00_disable(ucb);
537b53046cbSArnd Bergmann 	if (!ucb->irq) {
538f5ae587fSRussell King 		dev_err(&ucb->dev, "IRQ probe failed\n");
53905c45ca9SRussell King 		ret = -ENODEV;
540f5ae587fSRussell King 		goto err_no_irq;
54105c45ca9SRussell King 	}
54205c45ca9SRussell King 
5439ca3dc80SThomas Kunze 	ucb->gpio.base = -1;
544a3364409SRussell King 	irq_base = pdata ? pdata->irq_base : 0;
545a3364409SRussell King 	ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1);
546a3364409SRussell King 	if (ucb->irq_base < 0) {
547a3364409SRussell King 		dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n",
548a3364409SRussell King 			ucb->irq_base);
54918fefda9SWei Yongjun 		ret = ucb->irq_base;
550a3364409SRussell King 		goto err_irq_alloc;
551a3364409SRussell King 	}
552a3364409SRussell King 
553a3364409SRussell King 	for (i = 0; i < 16; i++) {
554a3364409SRussell King 		unsigned irq = ucb->irq_base + i;
555a3364409SRussell King 
556a3364409SRussell King 		irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq);
557a3364409SRussell King 		irq_set_chip_data(irq, ucb);
5589bd09f34SRob Herring 		irq_clear_status_flags(irq, IRQ_NOREQUEST);
559a3364409SRussell King 	}
560a3364409SRussell King 
561a3364409SRussell King 	irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING);
562056c0acfSRussell King 	irq_set_chained_handler_and_data(ucb->irq, ucb1x00_irq, ucb);
563a3364409SRussell King 
564abe06082SRussell King 	if (pdata && pdata->gpio_base) {
5659ca3dc80SThomas Kunze 		ucb->gpio.label = dev_name(&ucb->dev);
56658383c78SLinus Walleij 		ucb->gpio.parent = &ucb->dev;
5677655b2acSRussell King 		ucb->gpio.owner = THIS_MODULE;
568abe06082SRussell King 		ucb->gpio.base = pdata->gpio_base;
5699ca3dc80SThomas Kunze 		ucb->gpio.ngpio = 10;
5709ca3dc80SThomas Kunze 		ucb->gpio.set = ucb1x00_gpio_set;
5719ca3dc80SThomas Kunze 		ucb->gpio.get = ucb1x00_gpio_get;
5729ca3dc80SThomas Kunze 		ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
5739ca3dc80SThomas Kunze 		ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
574a3364409SRussell King 		ucb->gpio.to_irq = ucb1x00_to_irq;
5757d94352eSLinus Walleij 		ret = gpiochip_add_data(&ucb->gpio, ucb);
5769ca3dc80SThomas Kunze 		if (ret)
577f5ae587fSRussell King 			goto err_gpio_add;
5789ca3dc80SThomas Kunze 	} else
5799ca3dc80SThomas Kunze 		dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
5809ca3dc80SThomas Kunze 
58105c45ca9SRussell King 	mcp_set_drvdata(mcp, ucb);
58205c45ca9SRussell King 
58333237616SRussell King 	if (pdata)
58433237616SRussell King 		device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
58533237616SRussell King 
58605c45ca9SRussell King 	INIT_LIST_HEAD(&ucb->devs);
587a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
58865b539bbSRussell King 	list_add_tail(&ucb->node, &ucb1x00_devices);
58905c45ca9SRussell King 	list_for_each_entry(drv, &ucb1x00_drivers, node) {
59005c45ca9SRussell King 		ucb1x00_add_dev(ucb, drv);
59105c45ca9SRussell King 	}
592a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
5939ca3dc80SThomas Kunze 
5942f7510c6SRussell King 	return ret;
59505c45ca9SRussell King 
596f5ae587fSRussell King  err_gpio_add:
597a3364409SRussell King 	irq_set_chained_handler(ucb->irq, NULL);
598a3364409SRussell King  err_irq_alloc:
599a3364409SRussell King 	if (ucb->irq_base > 0)
600a3364409SRussell King 		irq_free_descs(ucb->irq_base, 16);
601f5ae587fSRussell King  err_no_irq:
602f5ae587fSRussell King 	device_del(&ucb->dev);
603f5ae587fSRussell King  err_dev_add:
604f5ae587fSRussell King 	put_device(&ucb->dev);
60505c45ca9SRussell King  out:
6062f7510c6SRussell King 	if (pdata && pdata->reset)
6072f7510c6SRussell King 		pdata->reset(UCB_RST_PROBE_FAIL);
60805c45ca9SRussell King 	return ret;
60905c45ca9SRussell King }
61005c45ca9SRussell King 
ucb1x00_remove(struct mcp * mcp)61105c45ca9SRussell King static void ucb1x00_remove(struct mcp *mcp)
61205c45ca9SRussell King {
6132f7510c6SRussell King 	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
61405c45ca9SRussell King 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
61505c45ca9SRussell King 	struct list_head *l, *n;
61605c45ca9SRussell King 
617a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
61805c45ca9SRussell King 	list_del(&ucb->node);
61905c45ca9SRussell King 	list_for_each_safe(l, n, &ucb->devs) {
62005c45ca9SRussell King 		struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, dev_node);
62105c45ca9SRussell King 		ucb1x00_remove_dev(dev);
62205c45ca9SRussell King 	}
623a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
62405c45ca9SRussell King 
62588d5e520Sabdoulaye berthe 	if (ucb->gpio.base != -1)
62688d5e520Sabdoulaye berthe 		gpiochip_remove(&ucb->gpio);
6279ca3dc80SThomas Kunze 
628a3364409SRussell King 	irq_set_chained_handler(ucb->irq, NULL);
629a3364409SRussell King 	irq_free_descs(ucb->irq_base, 16);
6300c55445fSTony Jones 	device_unregister(&ucb->dev);
6312f7510c6SRussell King 
6322f7510c6SRussell King 	if (pdata && pdata->reset)
6332f7510c6SRussell King 		pdata->reset(UCB_RST_REMOVE);
63405c45ca9SRussell King }
63505c45ca9SRussell King 
ucb1x00_register_driver(struct ucb1x00_driver * drv)63605c45ca9SRussell King int ucb1x00_register_driver(struct ucb1x00_driver *drv)
63705c45ca9SRussell King {
63805c45ca9SRussell King 	struct ucb1x00 *ucb;
63905c45ca9SRussell King 
64005c45ca9SRussell King 	INIT_LIST_HEAD(&drv->devs);
641a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
64265b539bbSRussell King 	list_add_tail(&drv->node, &ucb1x00_drivers);
64305c45ca9SRussell King 	list_for_each_entry(ucb, &ucb1x00_devices, node) {
64405c45ca9SRussell King 		ucb1x00_add_dev(ucb, drv);
64505c45ca9SRussell King 	}
646a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
64705c45ca9SRussell King 	return 0;
64805c45ca9SRussell King }
64905c45ca9SRussell King 
ucb1x00_unregister_driver(struct ucb1x00_driver * drv)65005c45ca9SRussell King void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
65105c45ca9SRussell King {
65205c45ca9SRussell King 	struct list_head *n, *l;
65305c45ca9SRussell King 
654a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
65505c45ca9SRussell King 	list_del(&drv->node);
65605c45ca9SRussell King 	list_for_each_safe(l, n, &drv->devs) {
65705c45ca9SRussell King 		struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, drv_node);
65805c45ca9SRussell King 		ucb1x00_remove_dev(dev);
65905c45ca9SRussell King 	}
660a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
66105c45ca9SRussell King }
66205c45ca9SRussell King 
ucb1x00_suspend(struct device * dev)6635a09b712SRussell King static int ucb1x00_suspend(struct device *dev)
66405c45ca9SRussell King {
665334a41ceSJingoo Han 	struct ucb1x00_plat_data *pdata = dev_get_platdata(dev);
6665a09b712SRussell King 	struct ucb1x00 *ucb = dev_get_drvdata(dev);
6675a09b712SRussell King 	struct ucb1x00_dev *udev;
66805c45ca9SRussell King 
669a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
6705a09b712SRussell King 	list_for_each_entry(udev, &ucb->devs, dev_node) {
6715a09b712SRussell King 		if (udev->drv->suspend)
6725a09b712SRussell King 			udev->drv->suspend(udev);
67305c45ca9SRussell King 	}
674a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
67533237616SRussell King 
67633237616SRussell King 	if (ucb->irq_wake) {
67733237616SRussell King 		unsigned long flags;
67833237616SRussell King 
67933237616SRussell King 		raw_spin_lock_irqsave(&ucb->irq_lock, flags);
68033237616SRussell King 		ucb1x00_enable(ucb);
68133237616SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
68233237616SRussell King 				  ucb->irq_wake);
68333237616SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
68433237616SRussell King 				  ucb->irq_wake);
68533237616SRussell King 		ucb1x00_disable(ucb);
68633237616SRussell King 		raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
68733237616SRussell King 
68833237616SRussell King 		enable_irq_wake(ucb->irq);
68933237616SRussell King 	} else if (pdata && pdata->reset)
69033237616SRussell King 		pdata->reset(UCB_RST_SUSPEND);
69133237616SRussell King 
69205c45ca9SRussell King 	return 0;
69305c45ca9SRussell King }
69405c45ca9SRussell King 
ucb1x00_resume(struct device * dev)6955a09b712SRussell King static int ucb1x00_resume(struct device *dev)
69605c45ca9SRussell King {
697334a41ceSJingoo Han 	struct ucb1x00_plat_data *pdata = dev_get_platdata(dev);
6985a09b712SRussell King 	struct ucb1x00 *ucb = dev_get_drvdata(dev);
6995a09b712SRussell King 	struct ucb1x00_dev *udev;
70005c45ca9SRussell King 
70133237616SRussell King 	if (!ucb->irq_wake && pdata && pdata->reset)
70233237616SRussell King 		pdata->reset(UCB_RST_RESUME);
70333237616SRussell King 
704ed442b67SRussell King 	ucb1x00_enable(ucb);
7052e95e51eSRussell King 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
7069ca3dc80SThomas Kunze 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
70733237616SRussell King 
70833237616SRussell King 	if (ucb->irq_wake) {
70933237616SRussell King 		unsigned long flags;
71033237616SRussell King 
71133237616SRussell King 		raw_spin_lock_irqsave(&ucb->irq_lock, flags);
71233237616SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
71333237616SRussell King 				  ucb->irq_mask);
71433237616SRussell King 		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
71533237616SRussell King 				  ucb->irq_mask);
71633237616SRussell King 		raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
71733237616SRussell King 
71833237616SRussell King 		disable_irq_wake(ucb->irq);
71933237616SRussell King 	}
720ed442b67SRussell King 	ucb1x00_disable(ucb);
72133237616SRussell King 
722a621aaedSArjan van de Ven 	mutex_lock(&ucb1x00_mutex);
7235a09b712SRussell King 	list_for_each_entry(udev, &ucb->devs, dev_node) {
7245a09b712SRussell King 		if (udev->drv->resume)
7255a09b712SRussell King 			udev->drv->resume(udev);
72605c45ca9SRussell King 	}
727a621aaedSArjan van de Ven 	mutex_unlock(&ucb1x00_mutex);
72805c45ca9SRussell King 	return 0;
72905c45ca9SRussell King }
73005c45ca9SRussell King 
731*03bf96cfSPaul Cercueil static DEFINE_SIMPLE_DEV_PM_OPS(ucb1x00_pm_ops,
732*03bf96cfSPaul Cercueil 				ucb1x00_suspend, ucb1x00_resume);
7335a09b712SRussell King 
73405c45ca9SRussell King static struct mcp_driver ucb1x00_driver = {
73505c45ca9SRussell King 	.drv		= {
73605c45ca9SRussell King 		.name	= "ucb1x00",
737ddb1e04aSRussell King 		.owner	= THIS_MODULE,
738*03bf96cfSPaul Cercueil 		.pm	= pm_sleep_ptr(&ucb1x00_pm_ops),
73905c45ca9SRussell King 	},
74005c45ca9SRussell King 	.probe		= ucb1x00_probe,
74105c45ca9SRussell King 	.remove		= ucb1x00_remove,
74205c45ca9SRussell King };
74305c45ca9SRussell King 
ucb1x00_init(void)74405c45ca9SRussell King static int __init ucb1x00_init(void)
74505c45ca9SRussell King {
74605c45ca9SRussell King 	int ret = class_register(&ucb1x00_class);
74705c45ca9SRussell King 	if (ret == 0) {
74805c45ca9SRussell King 		ret = mcp_driver_register(&ucb1x00_driver);
74905c45ca9SRussell King 		if (ret)
75005c45ca9SRussell King 			class_unregister(&ucb1x00_class);
75105c45ca9SRussell King 	}
75205c45ca9SRussell King 	return ret;
75305c45ca9SRussell King }
75405c45ca9SRussell King 
ucb1x00_exit(void)75505c45ca9SRussell King static void __exit ucb1x00_exit(void)
75605c45ca9SRussell King {
75705c45ca9SRussell King 	mcp_driver_unregister(&ucb1x00_driver);
75805c45ca9SRussell King 	class_unregister(&ucb1x00_class);
75905c45ca9SRussell King }
76005c45ca9SRussell King 
76105c45ca9SRussell King module_init(ucb1x00_init);
76205c45ca9SRussell King module_exit(ucb1x00_exit);
76305c45ca9SRussell King 
76405c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_set_dir);
76505c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_write);
76605c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_read);
76705c45ca9SRussell King 
76805c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_enable);
76905c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_read);
77005c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_disable);
77105c45ca9SRussell King 
77205c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_register_driver);
77305c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_unregister_driver);
77405c45ca9SRussell King 
775ddb1e04aSRussell King MODULE_ALIAS("mcp:ucb1x00");
77605c45ca9SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
77705c45ca9SRussell King MODULE_DESCRIPTION("UCB1x00 core driver");
77805c45ca9SRussell King MODULE_LICENSE("GPL");
779