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