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> 26a3364409SRussell King #include <linux/irq.h> 2705c45ca9SRussell King #include <linux/device.h> 28a621aaedSArjan van de Ven #include <linux/mutex.h> 29c8602edfSThomas Kunze #include <linux/mfd/ucb1x00.h> 305a09b712SRussell King #include <linux/pm.h> 319ca3dc80SThomas Kunze #include <linux/gpio.h> 3205c45ca9SRussell King 33a621aaedSArjan van de Ven static DEFINE_MUTEX(ucb1x00_mutex); 3405c45ca9SRussell King static LIST_HEAD(ucb1x00_drivers); 3505c45ca9SRussell King static LIST_HEAD(ucb1x00_devices); 3605c45ca9SRussell King 3705c45ca9SRussell King /** 3805c45ca9SRussell King * ucb1x00_io_set_dir - set IO direction 3905c45ca9SRussell King * @ucb: UCB1x00 structure describing chip 4005c45ca9SRussell King * @in: bitfield of IO pins to be set as inputs 4105c45ca9SRussell King * @out: bitfield of IO pins to be set as outputs 4205c45ca9SRussell King * 4305c45ca9SRussell King * Set the IO direction of the ten general purpose IO pins on 4405c45ca9SRussell King * the UCB1x00 chip. The @in bitfield has priority over the 4505c45ca9SRussell King * @out bitfield, in that if you specify a pin as both input 4605c45ca9SRussell King * and output, it will end up as an input. 4705c45ca9SRussell King * 4805c45ca9SRussell King * ucb1x00_enable must have been called to enable the comms 4905c45ca9SRussell King * before using this function. 5005c45ca9SRussell King * 5105c45ca9SRussell King * This function takes a spinlock, disabling interrupts. 5205c45ca9SRussell King */ 5305c45ca9SRussell King void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out) 5405c45ca9SRussell King { 5505c45ca9SRussell King unsigned long flags; 5605c45ca9SRussell King 5705c45ca9SRussell King spin_lock_irqsave(&ucb->io_lock, flags); 5805c45ca9SRussell King ucb->io_dir |= out; 5905c45ca9SRussell King ucb->io_dir &= ~in; 6005c45ca9SRussell King 6105c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); 6205c45ca9SRussell King spin_unlock_irqrestore(&ucb->io_lock, flags); 6305c45ca9SRussell King } 6405c45ca9SRussell King 6505c45ca9SRussell King /** 6605c45ca9SRussell King * ucb1x00_io_write - set or clear IO outputs 6705c45ca9SRussell King * @ucb: UCB1x00 structure describing chip 6805c45ca9SRussell King * @set: bitfield of IO pins to set to logic '1' 6905c45ca9SRussell King * @clear: bitfield of IO pins to set to logic '0' 7005c45ca9SRussell King * 7105c45ca9SRussell King * Set the IO output state of the specified IO pins. The value 7205c45ca9SRussell King * is retained if the pins are subsequently configured as inputs. 7305c45ca9SRussell King * The @clear bitfield has priority over the @set bitfield - 7405c45ca9SRussell King * outputs will be cleared. 7505c45ca9SRussell King * 7605c45ca9SRussell King * ucb1x00_enable must have been called to enable the comms 7705c45ca9SRussell King * before using this function. 7805c45ca9SRussell King * 7905c45ca9SRussell King * This function takes a spinlock, disabling interrupts. 8005c45ca9SRussell King */ 8105c45ca9SRussell King void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear) 8205c45ca9SRussell King { 8305c45ca9SRussell King unsigned long flags; 8405c45ca9SRussell King 8505c45ca9SRussell King spin_lock_irqsave(&ucb->io_lock, flags); 8605c45ca9SRussell King ucb->io_out |= set; 8705c45ca9SRussell King ucb->io_out &= ~clear; 8805c45ca9SRussell King 8905c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 9005c45ca9SRussell King spin_unlock_irqrestore(&ucb->io_lock, flags); 9105c45ca9SRussell King } 9205c45ca9SRussell King 9305c45ca9SRussell King /** 9405c45ca9SRussell King * ucb1x00_io_read - read the current state of the IO pins 9505c45ca9SRussell King * @ucb: UCB1x00 structure describing chip 9605c45ca9SRussell King * 9705c45ca9SRussell King * Return a bitfield describing the logic state of the ten 9805c45ca9SRussell King * general purpose IO pins. 9905c45ca9SRussell King * 10005c45ca9SRussell King * ucb1x00_enable must have been called to enable the comms 10105c45ca9SRussell King * before using this function. 10205c45ca9SRussell King * 103cae15476SRussell King * This function does not take any mutexes or spinlocks. 10405c45ca9SRussell King */ 10505c45ca9SRussell King unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) 10605c45ca9SRussell King { 10705c45ca9SRussell King return ucb1x00_reg_read(ucb, UCB_IO_DATA); 10805c45ca9SRussell King } 10905c45ca9SRussell King 1109ca3dc80SThomas Kunze static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1119ca3dc80SThomas Kunze { 1129ca3dc80SThomas Kunze struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); 1139ca3dc80SThomas Kunze unsigned long flags; 1149ca3dc80SThomas Kunze 1159ca3dc80SThomas Kunze spin_lock_irqsave(&ucb->io_lock, flags); 1169ca3dc80SThomas Kunze if (value) 1179ca3dc80SThomas Kunze ucb->io_out |= 1 << offset; 1189ca3dc80SThomas Kunze else 1199ca3dc80SThomas Kunze ucb->io_out &= ~(1 << offset); 1209ca3dc80SThomas Kunze 121ed442b67SRussell King ucb1x00_enable(ucb); 1229ca3dc80SThomas Kunze ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 123ed442b67SRussell King ucb1x00_disable(ucb); 1249ca3dc80SThomas Kunze spin_unlock_irqrestore(&ucb->io_lock, flags); 1259ca3dc80SThomas Kunze } 1269ca3dc80SThomas Kunze 1279ca3dc80SThomas Kunze static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) 1289ca3dc80SThomas Kunze { 1299ca3dc80SThomas Kunze struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); 130ed442b67SRussell King unsigned val; 131ed442b67SRussell King 132ed442b67SRussell King ucb1x00_enable(ucb); 133ed442b67SRussell King val = ucb1x00_reg_read(ucb, UCB_IO_DATA); 134ed442b67SRussell King ucb1x00_disable(ucb); 135ed442b67SRussell King 136ed442b67SRussell King return val & (1 << offset); 1379ca3dc80SThomas Kunze } 1389ca3dc80SThomas Kunze 1399ca3dc80SThomas Kunze static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 1409ca3dc80SThomas Kunze { 1419ca3dc80SThomas Kunze struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); 1429ca3dc80SThomas Kunze unsigned long flags; 1439ca3dc80SThomas Kunze 1449ca3dc80SThomas Kunze spin_lock_irqsave(&ucb->io_lock, flags); 1459ca3dc80SThomas Kunze ucb->io_dir &= ~(1 << offset); 146ed442b67SRussell King ucb1x00_enable(ucb); 1479ca3dc80SThomas Kunze ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); 148ed442b67SRussell King ucb1x00_disable(ucb); 1499ca3dc80SThomas Kunze spin_unlock_irqrestore(&ucb->io_lock, flags); 1509ca3dc80SThomas Kunze 1519ca3dc80SThomas Kunze return 0; 1529ca3dc80SThomas Kunze } 1539ca3dc80SThomas Kunze 1549ca3dc80SThomas Kunze static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset 1559ca3dc80SThomas Kunze , int value) 1569ca3dc80SThomas Kunze { 1579ca3dc80SThomas Kunze struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); 1589ca3dc80SThomas Kunze unsigned long flags; 159c23bb602SRussell King unsigned old, mask = 1 << offset; 1609ca3dc80SThomas Kunze 1619ca3dc80SThomas Kunze spin_lock_irqsave(&ucb->io_lock, flags); 162c23bb602SRussell King old = ucb->io_out; 1639ca3dc80SThomas Kunze if (value) 164c23bb602SRussell King ucb->io_out |= mask; 1659ca3dc80SThomas Kunze else 166c23bb602SRussell King ucb->io_out &= ~mask; 167c23bb602SRussell King 168ed442b67SRussell King ucb1x00_enable(ucb); 169c23bb602SRussell King if (old != ucb->io_out) 1709ca3dc80SThomas Kunze ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 171c23bb602SRussell King 172c23bb602SRussell King if (!(ucb->io_dir & mask)) { 173c23bb602SRussell King ucb->io_dir |= mask; 174c23bb602SRussell King ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); 175c23bb602SRussell King } 176ed442b67SRussell King ucb1x00_disable(ucb); 1779ca3dc80SThomas Kunze spin_unlock_irqrestore(&ucb->io_lock, flags); 1789ca3dc80SThomas Kunze 1799ca3dc80SThomas Kunze return 0; 1809ca3dc80SThomas Kunze } 1819ca3dc80SThomas Kunze 182a3364409SRussell King static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset) 183a3364409SRussell King { 184a3364409SRussell King struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); 185a3364409SRussell King 186a3364409SRussell King return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO; 187a3364409SRussell King } 188a3364409SRussell King 18905c45ca9SRussell King /* 19005c45ca9SRussell King * UCB1300 data sheet says we must: 19105c45ca9SRussell King * 1. enable ADC => 5us (including reference startup time) 19205c45ca9SRussell King * 2. select input => 51*tsibclk => 4.3us 19305c45ca9SRussell King * 3. start conversion => 102*tsibclk => 8.5us 19405c45ca9SRussell King * (tsibclk = 1/11981000) 19505c45ca9SRussell King * Period between SIB 128-bit frames = 10.7us 19605c45ca9SRussell King */ 19705c45ca9SRussell King 19805c45ca9SRussell King /** 19905c45ca9SRussell King * ucb1x00_adc_enable - enable the ADC converter 20005c45ca9SRussell King * @ucb: UCB1x00 structure describing chip 20105c45ca9SRussell King * 20205c45ca9SRussell King * Enable the ucb1x00 and ADC converter on the UCB1x00 for use. 20305c45ca9SRussell King * Any code wishing to use the ADC converter must call this 20405c45ca9SRussell King * function prior to using it. 20505c45ca9SRussell King * 206cae15476SRussell King * This function takes the ADC mutex to prevent two or more 20705c45ca9SRussell King * concurrent uses, and therefore may sleep. As a result, it 20805c45ca9SRussell King * can only be called from process context, not interrupt 20905c45ca9SRussell King * context. 21005c45ca9SRussell King * 21105c45ca9SRussell King * You should release the ADC as soon as possible using 21205c45ca9SRussell King * ucb1x00_adc_disable. 21305c45ca9SRussell King */ 21405c45ca9SRussell King void ucb1x00_adc_enable(struct ucb1x00 *ucb) 21505c45ca9SRussell King { 216cae15476SRussell King mutex_lock(&ucb->adc_mutex); 21705c45ca9SRussell King 21805c45ca9SRussell King ucb->adc_cr |= UCB_ADC_ENA; 21905c45ca9SRussell King 22005c45ca9SRussell King ucb1x00_enable(ucb); 22105c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); 22205c45ca9SRussell King } 22305c45ca9SRussell King 22405c45ca9SRussell King /** 22505c45ca9SRussell King * ucb1x00_adc_read - read the specified ADC channel 22605c45ca9SRussell King * @ucb: UCB1x00 structure describing chip 22705c45ca9SRussell King * @adc_channel: ADC channel mask 22805c45ca9SRussell King * @sync: wait for syncronisation pulse. 22905c45ca9SRussell King * 23005c45ca9SRussell King * Start an ADC conversion and wait for the result. Note that 23105c45ca9SRussell King * synchronised ADC conversions (via the ADCSYNC pin) must wait 23205c45ca9SRussell King * until the trigger is asserted and the conversion is finished. 23305c45ca9SRussell King * 23405c45ca9SRussell King * This function currently spins waiting for the conversion to 23505c45ca9SRussell King * complete (2 frames max without sync). 23605c45ca9SRussell King * 23705c45ca9SRussell King * If called for a synchronised ADC conversion, it may sleep 238cae15476SRussell King * with the ADC mutex held. 23905c45ca9SRussell King */ 24005c45ca9SRussell King unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) 24105c45ca9SRussell King { 24205c45ca9SRussell King unsigned int val; 24305c45ca9SRussell King 24405c45ca9SRussell King if (sync) 24505c45ca9SRussell King adc_channel |= UCB_ADC_SYNC_ENA; 24605c45ca9SRussell King 24705c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel); 24805c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START); 24905c45ca9SRussell King 25005c45ca9SRussell King for (;;) { 25105c45ca9SRussell King val = ucb1x00_reg_read(ucb, UCB_ADC_DATA); 25205c45ca9SRussell King if (val & UCB_ADC_DAT_VAL) 25305c45ca9SRussell King break; 25405c45ca9SRussell King /* yield to other processes */ 25505c45ca9SRussell King set_current_state(TASK_INTERRUPTIBLE); 25605c45ca9SRussell King schedule_timeout(1); 25705c45ca9SRussell King } 25805c45ca9SRussell King 25905c45ca9SRussell King return UCB_ADC_DAT(val); 26005c45ca9SRussell King } 26105c45ca9SRussell King 26205c45ca9SRussell King /** 26305c45ca9SRussell King * ucb1x00_adc_disable - disable the ADC converter 26405c45ca9SRussell King * @ucb: UCB1x00 structure describing chip 26505c45ca9SRussell King * 266cae15476SRussell King * Disable the ADC converter and release the ADC mutex. 26705c45ca9SRussell King */ 26805c45ca9SRussell King void ucb1x00_adc_disable(struct ucb1x00 *ucb) 26905c45ca9SRussell King { 27005c45ca9SRussell King ucb->adc_cr &= ~UCB_ADC_ENA; 27105c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); 27205c45ca9SRussell King ucb1x00_disable(ucb); 27305c45ca9SRussell King 274cae15476SRussell King mutex_unlock(&ucb->adc_mutex); 27505c45ca9SRussell King } 27605c45ca9SRussell King 27705c45ca9SRussell King /* 27805c45ca9SRussell King * UCB1x00 Interrupt handling. 27905c45ca9SRussell King * 28005c45ca9SRussell King * The UCB1x00 can generate interrupts when the SIBCLK is stopped. 28105c45ca9SRussell King * Since we need to read an internal register, we must re-enable 28205c45ca9SRussell King * SIBCLK to talk to the chip. We leave the clock running until 28305c45ca9SRussell King * we have finished processing all interrupts from the chip. 28405c45ca9SRussell King */ 285a3364409SRussell King static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc) 28605c45ca9SRussell King { 287a3364409SRussell King struct ucb1x00 *ucb = irq_desc_get_handler_data(desc); 28805c45ca9SRussell King unsigned int isr, i; 28905c45ca9SRussell King 29005c45ca9SRussell King ucb1x00_enable(ucb); 29105c45ca9SRussell King isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); 29205c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); 29305c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); 29405c45ca9SRussell King 295a3364409SRussell King for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++) 296a3364409SRussell King if (isr & 1) 297a3364409SRussell King generic_handle_irq(ucb->irq_base + i); 29805c45ca9SRussell King ucb1x00_disable(ucb); 29905c45ca9SRussell King } 30005c45ca9SRussell King 301a3364409SRussell King static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask) 30205c45ca9SRussell King { 30305c45ca9SRussell King ucb1x00_enable(ucb); 304a3364409SRussell King if (ucb->irq_ris_enbl & mask) 305a3364409SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & 306a3364409SRussell King ucb->irq_mask); 307a3364409SRussell King if (ucb->irq_fal_enbl & mask) 308a3364409SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & 309a3364409SRussell King ucb->irq_mask); 31005c45ca9SRussell King ucb1x00_disable(ucb); 31105c45ca9SRussell King } 31205c45ca9SRussell King 313a3364409SRussell King static void ucb1x00_irq_noop(struct irq_data *data) 31405c45ca9SRussell King { 31505c45ca9SRussell King } 31605c45ca9SRussell King 317a3364409SRussell King static void ucb1x00_irq_mask(struct irq_data *data) 31805c45ca9SRussell King { 319a3364409SRussell King struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); 320a3364409SRussell King unsigned mask = 1 << (data->irq - ucb->irq_base); 32105c45ca9SRussell King 322a3364409SRussell King raw_spin_lock(&ucb->irq_lock); 323a3364409SRussell King ucb->irq_mask &= ~mask; 324a3364409SRussell King ucb1x00_irq_update(ucb, mask); 325a3364409SRussell King raw_spin_unlock(&ucb->irq_lock); 32605c45ca9SRussell King } 32705c45ca9SRussell King 328a3364409SRussell King static void ucb1x00_irq_unmask(struct irq_data *data) 329a3364409SRussell King { 330a3364409SRussell King struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); 331a3364409SRussell King unsigned mask = 1 << (data->irq - ucb->irq_base); 332a3364409SRussell King 333a3364409SRussell King raw_spin_lock(&ucb->irq_lock); 334a3364409SRussell King ucb->irq_mask |= mask; 335a3364409SRussell King ucb1x00_irq_update(ucb, mask); 336a3364409SRussell King raw_spin_unlock(&ucb->irq_lock); 33705c45ca9SRussell King } 33805c45ca9SRussell King 339a3364409SRussell King static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type) 340a3364409SRussell King { 341a3364409SRussell King struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); 342a3364409SRussell King unsigned mask = 1 << (data->irq - ucb->irq_base); 343a3364409SRussell King 344a3364409SRussell King raw_spin_lock(&ucb->irq_lock); 345a3364409SRussell King if (type & IRQ_TYPE_EDGE_RISING) 346a3364409SRussell King ucb->irq_ris_enbl |= mask; 347a3364409SRussell King else 348a3364409SRussell King ucb->irq_ris_enbl &= ~mask; 349a3364409SRussell King 350a3364409SRussell King if (type & IRQ_TYPE_EDGE_FALLING) 351a3364409SRussell King ucb->irq_fal_enbl |= mask; 352a3364409SRussell King else 353a3364409SRussell King ucb->irq_fal_enbl &= ~mask; 354a3364409SRussell King if (ucb->irq_mask & mask) { 355a3364409SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & 356a3364409SRussell King ucb->irq_mask); 357a3364409SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & 358a3364409SRussell King ucb->irq_mask); 359a3364409SRussell King } 360a3364409SRussell King raw_spin_unlock(&ucb->irq_lock); 361a3364409SRussell King 362a3364409SRussell King return 0; 363a3364409SRussell King } 364a3364409SRussell King 36533237616SRussell King static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on) 36633237616SRussell King { 36733237616SRussell King struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); 36833237616SRussell King struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data; 36933237616SRussell King unsigned mask = 1 << (data->irq - ucb->irq_base); 37033237616SRussell King 37133237616SRussell King if (!pdata || !pdata->can_wakeup) 37233237616SRussell King return -EINVAL; 37333237616SRussell King 37433237616SRussell King raw_spin_lock(&ucb->irq_lock); 37533237616SRussell King if (on) 37633237616SRussell King ucb->irq_wake |= mask; 37733237616SRussell King else 37833237616SRussell King ucb->irq_wake &= ~mask; 37933237616SRussell King raw_spin_unlock(&ucb->irq_lock); 38033237616SRussell King 38133237616SRussell King return 0; 38233237616SRussell King } 38333237616SRussell King 384a3364409SRussell King static struct irq_chip ucb1x00_irqchip = { 385a3364409SRussell King .name = "ucb1x00", 386a3364409SRussell King .irq_ack = ucb1x00_irq_noop, 387a3364409SRussell King .irq_mask = ucb1x00_irq_mask, 388a3364409SRussell King .irq_unmask = ucb1x00_irq_unmask, 389a3364409SRussell King .irq_set_type = ucb1x00_irq_set_type, 39033237616SRussell King .irq_set_wake = ucb1x00_irq_set_wake, 391a3364409SRussell King }; 392a3364409SRussell King 39305c45ca9SRussell King static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) 39405c45ca9SRussell King { 39505c45ca9SRussell King struct ucb1x00_dev *dev; 39605c45ca9SRussell King int ret = -ENOMEM; 39705c45ca9SRussell King 39805c45ca9SRussell King dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL); 39905c45ca9SRussell King if (dev) { 40005c45ca9SRussell King dev->ucb = ucb; 40105c45ca9SRussell King dev->drv = drv; 40205c45ca9SRussell King 40305c45ca9SRussell King ret = drv->add(dev); 40405c45ca9SRussell King 40505c45ca9SRussell King if (ret == 0) { 40665b539bbSRussell King list_add_tail(&dev->dev_node, &ucb->devs); 40765b539bbSRussell King list_add_tail(&dev->drv_node, &drv->devs); 40805c45ca9SRussell King } else { 40905c45ca9SRussell King kfree(dev); 41005c45ca9SRussell King } 41105c45ca9SRussell King } 41205c45ca9SRussell King return ret; 41305c45ca9SRussell King } 41405c45ca9SRussell King 41505c45ca9SRussell King static void ucb1x00_remove_dev(struct ucb1x00_dev *dev) 41605c45ca9SRussell King { 41705c45ca9SRussell King dev->drv->remove(dev); 41805c45ca9SRussell King list_del(&dev->dev_node); 41905c45ca9SRussell King list_del(&dev->drv_node); 42005c45ca9SRussell King kfree(dev); 42105c45ca9SRussell King } 42205c45ca9SRussell King 42305c45ca9SRussell King /* 42405c45ca9SRussell King * Try to probe our interrupt, rather than relying on lots of 42505c45ca9SRussell King * hard-coded machine dependencies. For reference, the expected 42605c45ca9SRussell King * IRQ mappings are: 42705c45ca9SRussell King * 42805c45ca9SRussell King * Machine Default IRQ 42905c45ca9SRussell King * adsbitsy IRQ_GPCIN4 43005c45ca9SRussell King * cerf IRQ_GPIO_UCB1200_IRQ 43105c45ca9SRussell King * flexanet IRQ_GPIO_GUI 43205c45ca9SRussell King * freebird IRQ_GPIO_FREEBIRD_UCB1300_IRQ 43305c45ca9SRussell King * graphicsclient ADS_EXT_IRQ(8) 43405c45ca9SRussell King * graphicsmaster ADS_EXT_IRQ(8) 43505c45ca9SRussell King * lart LART_IRQ_UCB1200 43605c45ca9SRussell King * omnimeter IRQ_GPIO23 43705c45ca9SRussell King * pfs168 IRQ_GPIO_UCB1300_IRQ 43805c45ca9SRussell King * simpad IRQ_GPIO_UCB1300_IRQ 43905c45ca9SRussell King * shannon SHANNON_IRQ_GPIO_IRQ_CODEC 44005c45ca9SRussell King * yopy IRQ_GPIO_UCB1200_IRQ 44105c45ca9SRussell King */ 44205c45ca9SRussell King static int ucb1x00_detect_irq(struct ucb1x00 *ucb) 44305c45ca9SRussell King { 44405c45ca9SRussell King unsigned long mask; 44505c45ca9SRussell King 44605c45ca9SRussell King mask = probe_irq_on(); 447cfc73656SIngo Molnar if (!mask) { 448cfc73656SIngo Molnar probe_irq_off(mask); 44905c45ca9SRussell King return NO_IRQ; 450cfc73656SIngo Molnar } 45105c45ca9SRussell King 45205c45ca9SRussell King /* 45305c45ca9SRussell King * Enable the ADC interrupt. 45405c45ca9SRussell King */ 45505c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); 45605c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); 45705c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); 45805c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); 45905c45ca9SRussell King 46005c45ca9SRussell King /* 46105c45ca9SRussell King * Cause an ADC interrupt. 46205c45ca9SRussell King */ 46305c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); 46405c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); 46505c45ca9SRussell King 46605c45ca9SRussell King /* 46705c45ca9SRussell King * Wait for the conversion to complete. 46805c45ca9SRussell King */ 46905c45ca9SRussell King while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0); 47005c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, 0); 47105c45ca9SRussell King 47205c45ca9SRussell King /* 47305c45ca9SRussell King * Disable and clear interrupt. 47405c45ca9SRussell King */ 47505c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, 0); 47605c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, 0); 47705c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); 47805c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); 47905c45ca9SRussell King 48005c45ca9SRussell King /* 48105c45ca9SRussell King * Read triggered interrupt. 48205c45ca9SRussell King */ 48305c45ca9SRussell King return probe_irq_off(mask); 48405c45ca9SRussell King } 48505c45ca9SRussell King 4860c55445fSTony Jones static void ucb1x00_release(struct device *dev) 487585f5457SNicolas Pitre { 488585f5457SNicolas Pitre struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); 489585f5457SNicolas Pitre kfree(ucb); 490585f5457SNicolas Pitre } 491585f5457SNicolas Pitre 492585f5457SNicolas Pitre static struct class ucb1x00_class = { 493585f5457SNicolas Pitre .name = "ucb1x00", 4940c55445fSTony Jones .dev_release = ucb1x00_release, 495585f5457SNicolas Pitre }; 496585f5457SNicolas Pitre 49705c45ca9SRussell King static int ucb1x00_probe(struct mcp *mcp) 49805c45ca9SRussell King { 4992f7510c6SRussell King struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; 50005c45ca9SRussell King struct ucb1x00_driver *drv; 5012f7510c6SRussell King struct ucb1x00 *ucb; 502a3364409SRussell King unsigned id, i, irq_base; 50305c45ca9SRussell King int ret = -ENODEV; 50405c45ca9SRussell King 5052f7510c6SRussell King /* Tell the platform to deassert the UCB1x00 reset */ 5062f7510c6SRussell King if (pdata && pdata->reset) 5072f7510c6SRussell King pdata->reset(UCB_RST_PROBE); 5082f7510c6SRussell King 50905c45ca9SRussell King mcp_enable(mcp); 51005c45ca9SRussell King id = mcp_reg_read(mcp, UCB_ID); 5112b4d9d2bSRussell King mcp_disable(mcp); 51205c45ca9SRussell King 51365f2e753SRussell King if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { 51465f2e753SRussell King printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); 5152b4d9d2bSRussell King goto out; 51605c45ca9SRussell King } 51705c45ca9SRussell King 518dd00cc48SYoann Padioleau ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL); 51905c45ca9SRussell King ret = -ENOMEM; 52005c45ca9SRussell King if (!ucb) 5212b4d9d2bSRussell King goto out; 52205c45ca9SRussell King 523f5ae587fSRussell King device_initialize(&ucb->dev); 5240c55445fSTony Jones ucb->dev.class = &ucb1x00_class; 5250c55445fSTony Jones ucb->dev.parent = &mcp->attached_device; 52665f2e753SRussell King dev_set_name(&ucb->dev, "ucb1x00"); 52705c45ca9SRussell King 528a3364409SRussell King raw_spin_lock_init(&ucb->irq_lock); 52905c45ca9SRussell King spin_lock_init(&ucb->io_lock); 530cae15476SRussell King mutex_init(&ucb->adc_mutex); 53105c45ca9SRussell King 53265f2e753SRussell King ucb->id = id; 53305c45ca9SRussell King ucb->mcp = mcp; 534f5ae587fSRussell King 535f5ae587fSRussell King ret = device_add(&ucb->dev); 536f5ae587fSRussell King if (ret) 537f5ae587fSRussell King goto err_dev_add; 538f5ae587fSRussell King 5392b4d9d2bSRussell King ucb1x00_enable(ucb); 54005c45ca9SRussell King ucb->irq = ucb1x00_detect_irq(ucb); 5412b4d9d2bSRussell King ucb1x00_disable(ucb); 54205c45ca9SRussell King if (ucb->irq == NO_IRQ) { 543f5ae587fSRussell King dev_err(&ucb->dev, "IRQ probe failed\n"); 54405c45ca9SRussell King ret = -ENODEV; 545f5ae587fSRussell King goto err_no_irq; 54605c45ca9SRussell King } 54705c45ca9SRussell King 5489ca3dc80SThomas Kunze ucb->gpio.base = -1; 549a3364409SRussell King irq_base = pdata ? pdata->irq_base : 0; 550a3364409SRussell King ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1); 551a3364409SRussell King if (ucb->irq_base < 0) { 552a3364409SRussell King dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n", 553a3364409SRussell King ucb->irq_base); 554a3364409SRussell King goto err_irq_alloc; 555a3364409SRussell King } 556a3364409SRussell King 557a3364409SRussell King for (i = 0; i < 16; i++) { 558a3364409SRussell King unsigned irq = ucb->irq_base + i; 559a3364409SRussell King 560a3364409SRussell King irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq); 561a3364409SRussell King irq_set_chip_data(irq, ucb); 562a3364409SRussell King set_irq_flags(irq, IRQF_VALID | IRQ_NOREQUEST); 563a3364409SRussell King } 564a3364409SRussell King 565a3364409SRussell King irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING); 566a3364409SRussell King irq_set_handler_data(ucb->irq, ucb); 567a3364409SRussell King irq_set_chained_handler(ucb->irq, ucb1x00_irq); 568a3364409SRussell King 569abe06082SRussell King if (pdata && pdata->gpio_base) { 5709ca3dc80SThomas Kunze ucb->gpio.label = dev_name(&ucb->dev); 5717655b2acSRussell King ucb->gpio.dev = &ucb->dev; 5727655b2acSRussell King ucb->gpio.owner = THIS_MODULE; 573abe06082SRussell King ucb->gpio.base = pdata->gpio_base; 5749ca3dc80SThomas Kunze ucb->gpio.ngpio = 10; 5759ca3dc80SThomas Kunze ucb->gpio.set = ucb1x00_gpio_set; 5769ca3dc80SThomas Kunze ucb->gpio.get = ucb1x00_gpio_get; 5779ca3dc80SThomas Kunze ucb->gpio.direction_input = ucb1x00_gpio_direction_input; 5789ca3dc80SThomas Kunze ucb->gpio.direction_output = ucb1x00_gpio_direction_output; 579a3364409SRussell King ucb->gpio.to_irq = ucb1x00_to_irq; 5809ca3dc80SThomas Kunze ret = gpiochip_add(&ucb->gpio); 5819ca3dc80SThomas Kunze if (ret) 582f5ae587fSRussell King goto err_gpio_add; 5839ca3dc80SThomas Kunze } else 5849ca3dc80SThomas Kunze dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); 5859ca3dc80SThomas Kunze 58605c45ca9SRussell King mcp_set_drvdata(mcp, ucb); 58705c45ca9SRussell King 58833237616SRussell King if (pdata) 58933237616SRussell King device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup); 59033237616SRussell King 59105c45ca9SRussell King INIT_LIST_HEAD(&ucb->devs); 592a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 59365b539bbSRussell King list_add_tail(&ucb->node, &ucb1x00_devices); 59405c45ca9SRussell King list_for_each_entry(drv, &ucb1x00_drivers, node) { 59505c45ca9SRussell King ucb1x00_add_dev(ucb, drv); 59605c45ca9SRussell King } 597a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 5989ca3dc80SThomas Kunze 5992f7510c6SRussell King return ret; 60005c45ca9SRussell King 601f5ae587fSRussell King err_gpio_add: 602a3364409SRussell King irq_set_chained_handler(ucb->irq, NULL); 603a3364409SRussell King err_irq_alloc: 604a3364409SRussell King if (ucb->irq_base > 0) 605a3364409SRussell King irq_free_descs(ucb->irq_base, 16); 606f5ae587fSRussell King err_no_irq: 607f5ae587fSRussell King device_del(&ucb->dev); 608f5ae587fSRussell King err_dev_add: 609f5ae587fSRussell King put_device(&ucb->dev); 61005c45ca9SRussell King out: 6112f7510c6SRussell King if (pdata && pdata->reset) 6122f7510c6SRussell King pdata->reset(UCB_RST_PROBE_FAIL); 61305c45ca9SRussell King return ret; 61405c45ca9SRussell King } 61505c45ca9SRussell King 61605c45ca9SRussell King static void ucb1x00_remove(struct mcp *mcp) 61705c45ca9SRussell King { 6182f7510c6SRussell King struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; 61905c45ca9SRussell King struct ucb1x00 *ucb = mcp_get_drvdata(mcp); 62005c45ca9SRussell King struct list_head *l, *n; 6219ca3dc80SThomas Kunze int ret; 62205c45ca9SRussell King 623a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 62405c45ca9SRussell King list_del(&ucb->node); 62505c45ca9SRussell King list_for_each_safe(l, n, &ucb->devs) { 62605c45ca9SRussell King struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, dev_node); 62705c45ca9SRussell King ucb1x00_remove_dev(dev); 62805c45ca9SRussell King } 629a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 63005c45ca9SRussell King 6319ca3dc80SThomas Kunze if (ucb->gpio.base != -1) { 6329ca3dc80SThomas Kunze ret = gpiochip_remove(&ucb->gpio); 6339ca3dc80SThomas Kunze if (ret) 6349ca3dc80SThomas Kunze dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret); 6359ca3dc80SThomas Kunze } 6369ca3dc80SThomas Kunze 637a3364409SRussell King irq_set_chained_handler(ucb->irq, NULL); 638a3364409SRussell King irq_free_descs(ucb->irq_base, 16); 6390c55445fSTony Jones device_unregister(&ucb->dev); 6402f7510c6SRussell King 6412f7510c6SRussell King if (pdata && pdata->reset) 6422f7510c6SRussell King pdata->reset(UCB_RST_REMOVE); 64305c45ca9SRussell King } 64405c45ca9SRussell King 64505c45ca9SRussell King int ucb1x00_register_driver(struct ucb1x00_driver *drv) 64605c45ca9SRussell King { 64705c45ca9SRussell King struct ucb1x00 *ucb; 64805c45ca9SRussell King 64905c45ca9SRussell King INIT_LIST_HEAD(&drv->devs); 650a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 65165b539bbSRussell King list_add_tail(&drv->node, &ucb1x00_drivers); 65205c45ca9SRussell King list_for_each_entry(ucb, &ucb1x00_devices, node) { 65305c45ca9SRussell King ucb1x00_add_dev(ucb, drv); 65405c45ca9SRussell King } 655a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 65605c45ca9SRussell King return 0; 65705c45ca9SRussell King } 65805c45ca9SRussell King 65905c45ca9SRussell King void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) 66005c45ca9SRussell King { 66105c45ca9SRussell King struct list_head *n, *l; 66205c45ca9SRussell King 663a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 66405c45ca9SRussell King list_del(&drv->node); 66505c45ca9SRussell King list_for_each_safe(l, n, &drv->devs) { 66605c45ca9SRussell King struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, drv_node); 66705c45ca9SRussell King ucb1x00_remove_dev(dev); 66805c45ca9SRussell King } 669a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 67005c45ca9SRussell King } 67105c45ca9SRussell King 6725a09b712SRussell King static int ucb1x00_suspend(struct device *dev) 67305c45ca9SRussell King { 674334a41ceSJingoo Han struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); 6755a09b712SRussell King struct ucb1x00 *ucb = dev_get_drvdata(dev); 6765a09b712SRussell King struct ucb1x00_dev *udev; 67705c45ca9SRussell King 678a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 6795a09b712SRussell King list_for_each_entry(udev, &ucb->devs, dev_node) { 6805a09b712SRussell King if (udev->drv->suspend) 6815a09b712SRussell King udev->drv->suspend(udev); 68205c45ca9SRussell King } 683a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 68433237616SRussell King 68533237616SRussell King if (ucb->irq_wake) { 68633237616SRussell King unsigned long flags; 68733237616SRussell King 68833237616SRussell King raw_spin_lock_irqsave(&ucb->irq_lock, flags); 68933237616SRussell King ucb1x00_enable(ucb); 69033237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & 69133237616SRussell King ucb->irq_wake); 69233237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & 69333237616SRussell King ucb->irq_wake); 69433237616SRussell King ucb1x00_disable(ucb); 69533237616SRussell King raw_spin_unlock_irqrestore(&ucb->irq_lock, flags); 69633237616SRussell King 69733237616SRussell King enable_irq_wake(ucb->irq); 69833237616SRussell King } else if (pdata && pdata->reset) 69933237616SRussell King pdata->reset(UCB_RST_SUSPEND); 70033237616SRussell King 70105c45ca9SRussell King return 0; 70205c45ca9SRussell King } 70305c45ca9SRussell King 7045a09b712SRussell King static int ucb1x00_resume(struct device *dev) 70505c45ca9SRussell King { 706334a41ceSJingoo Han struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); 7075a09b712SRussell King struct ucb1x00 *ucb = dev_get_drvdata(dev); 7085a09b712SRussell King struct ucb1x00_dev *udev; 70905c45ca9SRussell King 71033237616SRussell King if (!ucb->irq_wake && pdata && pdata->reset) 71133237616SRussell King pdata->reset(UCB_RST_RESUME); 71233237616SRussell King 713ed442b67SRussell King ucb1x00_enable(ucb); 7142e95e51eSRussell King ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 7159ca3dc80SThomas Kunze ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); 71633237616SRussell King 71733237616SRussell King if (ucb->irq_wake) { 71833237616SRussell King unsigned long flags; 71933237616SRussell King 72033237616SRussell King raw_spin_lock_irqsave(&ucb->irq_lock, flags); 72133237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & 72233237616SRussell King ucb->irq_mask); 72333237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & 72433237616SRussell King ucb->irq_mask); 72533237616SRussell King raw_spin_unlock_irqrestore(&ucb->irq_lock, flags); 72633237616SRussell King 72733237616SRussell King disable_irq_wake(ucb->irq); 72833237616SRussell King } 729ed442b67SRussell King ucb1x00_disable(ucb); 73033237616SRussell King 731a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 7325a09b712SRussell King list_for_each_entry(udev, &ucb->devs, dev_node) { 7335a09b712SRussell King if (udev->drv->resume) 7345a09b712SRussell King udev->drv->resume(udev); 73505c45ca9SRussell King } 736a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 73705c45ca9SRussell King return 0; 73805c45ca9SRussell King } 73905c45ca9SRussell King 7405a09b712SRussell King static const struct dev_pm_ops ucb1x00_pm_ops = { 7415a09b712SRussell King SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume) 7425a09b712SRussell King }; 7435a09b712SRussell King 74405c45ca9SRussell King static struct mcp_driver ucb1x00_driver = { 74505c45ca9SRussell King .drv = { 74605c45ca9SRussell King .name = "ucb1x00", 747ddb1e04aSRussell King .owner = THIS_MODULE, 7485a09b712SRussell King .pm = &ucb1x00_pm_ops, 74905c45ca9SRussell King }, 75005c45ca9SRussell King .probe = ucb1x00_probe, 75105c45ca9SRussell King .remove = ucb1x00_remove, 75205c45ca9SRussell King }; 75305c45ca9SRussell King 75405c45ca9SRussell King static int __init ucb1x00_init(void) 75505c45ca9SRussell King { 75605c45ca9SRussell King int ret = class_register(&ucb1x00_class); 75705c45ca9SRussell King if (ret == 0) { 75805c45ca9SRussell King ret = mcp_driver_register(&ucb1x00_driver); 75905c45ca9SRussell King if (ret) 76005c45ca9SRussell King class_unregister(&ucb1x00_class); 76105c45ca9SRussell King } 76205c45ca9SRussell King return ret; 76305c45ca9SRussell King } 76405c45ca9SRussell King 76505c45ca9SRussell King static void __exit ucb1x00_exit(void) 76605c45ca9SRussell King { 76705c45ca9SRussell King mcp_driver_unregister(&ucb1x00_driver); 76805c45ca9SRussell King class_unregister(&ucb1x00_class); 76905c45ca9SRussell King } 77005c45ca9SRussell King 77105c45ca9SRussell King module_init(ucb1x00_init); 77205c45ca9SRussell King module_exit(ucb1x00_exit); 77305c45ca9SRussell King 77405c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_set_dir); 77505c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_write); 77605c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_read); 77705c45ca9SRussell King 77805c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_enable); 77905c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_read); 78005c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_disable); 78105c45ca9SRussell King 78205c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_register_driver); 78305c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_unregister_driver); 78405c45ca9SRussell King 785ddb1e04aSRussell King MODULE_ALIAS("mcp:ucb1x00"); 78605c45ca9SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); 78705c45ca9SRussell King MODULE_DESCRIPTION("UCB1x00 core driver"); 78805c45ca9SRussell King MODULE_LICENSE("GPL"); 789