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 */ 285bd0b9ac4SThomas Gleixner static void ucb1x00_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 2950d674d93SThomas Gleixner for (i = 0; i < 16 && isr; i++, isr >>= 1) 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; 39602a0bf6eSLee Jones int ret; 39705c45ca9SRussell King 39805c45ca9SRussell King dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL); 39902a0bf6eSLee Jones if (!dev) 40002a0bf6eSLee Jones return -ENOMEM; 40102a0bf6eSLee Jones 40205c45ca9SRussell King dev->ucb = ucb; 40305c45ca9SRussell King dev->drv = drv; 40405c45ca9SRussell King 40505c45ca9SRussell King ret = drv->add(dev); 40602a0bf6eSLee Jones if (ret) { 40702a0bf6eSLee Jones kfree(dev); 40802a0bf6eSLee Jones return ret; 40902a0bf6eSLee Jones } 41005c45ca9SRussell King 41165b539bbSRussell King list_add_tail(&dev->dev_node, &ucb->devs); 41265b539bbSRussell King list_add_tail(&dev->drv_node, &drv->devs); 41302a0bf6eSLee Jones 41405c45ca9SRussell King return ret; 41505c45ca9SRussell King } 41605c45ca9SRussell King 41705c45ca9SRussell King static void ucb1x00_remove_dev(struct ucb1x00_dev *dev) 41805c45ca9SRussell King { 41905c45ca9SRussell King dev->drv->remove(dev); 42005c45ca9SRussell King list_del(&dev->dev_node); 42105c45ca9SRussell King list_del(&dev->drv_node); 42205c45ca9SRussell King kfree(dev); 42305c45ca9SRussell King } 42405c45ca9SRussell King 42505c45ca9SRussell King /* 42605c45ca9SRussell King * Try to probe our interrupt, rather than relying on lots of 42705c45ca9SRussell King * hard-coded machine dependencies. For reference, the expected 42805c45ca9SRussell King * IRQ mappings are: 42905c45ca9SRussell King * 43005c45ca9SRussell King * Machine Default IRQ 43105c45ca9SRussell King * adsbitsy IRQ_GPCIN4 43205c45ca9SRussell King * cerf IRQ_GPIO_UCB1200_IRQ 43305c45ca9SRussell King * flexanet IRQ_GPIO_GUI 43405c45ca9SRussell King * freebird IRQ_GPIO_FREEBIRD_UCB1300_IRQ 43505c45ca9SRussell King * graphicsclient ADS_EXT_IRQ(8) 43605c45ca9SRussell King * graphicsmaster ADS_EXT_IRQ(8) 43705c45ca9SRussell King * lart LART_IRQ_UCB1200 43805c45ca9SRussell King * omnimeter IRQ_GPIO23 43905c45ca9SRussell King * pfs168 IRQ_GPIO_UCB1300_IRQ 44005c45ca9SRussell King * simpad IRQ_GPIO_UCB1300_IRQ 44105c45ca9SRussell King * shannon SHANNON_IRQ_GPIO_IRQ_CODEC 44205c45ca9SRussell King * yopy IRQ_GPIO_UCB1200_IRQ 44305c45ca9SRussell King */ 44405c45ca9SRussell King static int ucb1x00_detect_irq(struct ucb1x00 *ucb) 44505c45ca9SRussell King { 44605c45ca9SRussell King unsigned long mask; 44705c45ca9SRussell King 44805c45ca9SRussell King mask = probe_irq_on(); 449cfc73656SIngo Molnar if (!mask) { 450cfc73656SIngo Molnar probe_irq_off(mask); 45105c45ca9SRussell King return NO_IRQ; 452cfc73656SIngo Molnar } 45305c45ca9SRussell King 45405c45ca9SRussell King /* 45505c45ca9SRussell King * Enable the ADC interrupt. 45605c45ca9SRussell King */ 45705c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); 45805c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); 45905c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); 46005c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); 46105c45ca9SRussell King 46205c45ca9SRussell King /* 46305c45ca9SRussell King * Cause an ADC interrupt. 46405c45ca9SRussell King */ 46505c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); 46605c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); 46705c45ca9SRussell King 46805c45ca9SRussell King /* 46905c45ca9SRussell King * Wait for the conversion to complete. 47005c45ca9SRussell King */ 47105c45ca9SRussell King while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0); 47205c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_ADC_CR, 0); 47305c45ca9SRussell King 47405c45ca9SRussell King /* 47505c45ca9SRussell King * Disable and clear interrupt. 47605c45ca9SRussell King */ 47705c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, 0); 47805c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, 0); 47905c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); 48005c45ca9SRussell King ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); 48105c45ca9SRussell King 48205c45ca9SRussell King /* 48305c45ca9SRussell King * Read triggered interrupt. 48405c45ca9SRussell King */ 48505c45ca9SRussell King return probe_irq_off(mask); 48605c45ca9SRussell King } 48705c45ca9SRussell King 4880c55445fSTony Jones static void ucb1x00_release(struct device *dev) 489585f5457SNicolas Pitre { 490585f5457SNicolas Pitre struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); 491585f5457SNicolas Pitre kfree(ucb); 492585f5457SNicolas Pitre } 493585f5457SNicolas Pitre 494585f5457SNicolas Pitre static struct class ucb1x00_class = { 495585f5457SNicolas Pitre .name = "ucb1x00", 4960c55445fSTony Jones .dev_release = ucb1x00_release, 497585f5457SNicolas Pitre }; 498585f5457SNicolas Pitre 49905c45ca9SRussell King static int ucb1x00_probe(struct mcp *mcp) 50005c45ca9SRussell King { 5012f7510c6SRussell King struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; 50205c45ca9SRussell King struct ucb1x00_driver *drv; 5032f7510c6SRussell King struct ucb1x00 *ucb; 504a3364409SRussell King unsigned id, i, irq_base; 50505c45ca9SRussell King int ret = -ENODEV; 50605c45ca9SRussell King 5072f7510c6SRussell King /* Tell the platform to deassert the UCB1x00 reset */ 5082f7510c6SRussell King if (pdata && pdata->reset) 5092f7510c6SRussell King pdata->reset(UCB_RST_PROBE); 5102f7510c6SRussell King 51105c45ca9SRussell King mcp_enable(mcp); 51205c45ca9SRussell King id = mcp_reg_read(mcp, UCB_ID); 5132b4d9d2bSRussell King mcp_disable(mcp); 51405c45ca9SRussell King 51565f2e753SRussell King if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { 51665f2e753SRussell King printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); 5172b4d9d2bSRussell King goto out; 51805c45ca9SRussell King } 51905c45ca9SRussell King 520dd00cc48SYoann Padioleau ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL); 52105c45ca9SRussell King ret = -ENOMEM; 52205c45ca9SRussell King if (!ucb) 5232b4d9d2bSRussell King goto out; 52405c45ca9SRussell King 525f5ae587fSRussell King device_initialize(&ucb->dev); 5260c55445fSTony Jones ucb->dev.class = &ucb1x00_class; 5270c55445fSTony Jones ucb->dev.parent = &mcp->attached_device; 52865f2e753SRussell King dev_set_name(&ucb->dev, "ucb1x00"); 52905c45ca9SRussell King 530a3364409SRussell King raw_spin_lock_init(&ucb->irq_lock); 53105c45ca9SRussell King spin_lock_init(&ucb->io_lock); 532cae15476SRussell King mutex_init(&ucb->adc_mutex); 53305c45ca9SRussell King 53465f2e753SRussell King ucb->id = id; 53505c45ca9SRussell King ucb->mcp = mcp; 536f5ae587fSRussell King 537f5ae587fSRussell King ret = device_add(&ucb->dev); 538f5ae587fSRussell King if (ret) 539f5ae587fSRussell King goto err_dev_add; 540f5ae587fSRussell King 5412b4d9d2bSRussell King ucb1x00_enable(ucb); 54205c45ca9SRussell King ucb->irq = ucb1x00_detect_irq(ucb); 5432b4d9d2bSRussell King ucb1x00_disable(ucb); 54405c45ca9SRussell King if (ucb->irq == NO_IRQ) { 545f5ae587fSRussell King dev_err(&ucb->dev, "IRQ probe failed\n"); 54605c45ca9SRussell King ret = -ENODEV; 547f5ae587fSRussell King goto err_no_irq; 54805c45ca9SRussell King } 54905c45ca9SRussell King 5509ca3dc80SThomas Kunze ucb->gpio.base = -1; 551a3364409SRussell King irq_base = pdata ? pdata->irq_base : 0; 552a3364409SRussell King ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1); 553a3364409SRussell King if (ucb->irq_base < 0) { 554a3364409SRussell King dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n", 555a3364409SRussell King ucb->irq_base); 55618fefda9SWei Yongjun ret = ucb->irq_base; 557a3364409SRussell King goto err_irq_alloc; 558a3364409SRussell King } 559a3364409SRussell King 560a3364409SRussell King for (i = 0; i < 16; i++) { 561a3364409SRussell King unsigned irq = ucb->irq_base + i; 562a3364409SRussell King 563a3364409SRussell King irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq); 564a3364409SRussell King irq_set_chip_data(irq, ucb); 5659bd09f34SRob Herring irq_clear_status_flags(irq, IRQ_NOREQUEST); 566a3364409SRussell King } 567a3364409SRussell King 568a3364409SRussell King irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING); 569056c0acfSRussell King irq_set_chained_handler_and_data(ucb->irq, ucb1x00_irq, ucb); 570a3364409SRussell King 571abe06082SRussell King if (pdata && pdata->gpio_base) { 5729ca3dc80SThomas Kunze ucb->gpio.label = dev_name(&ucb->dev); 57358383c78SLinus Walleij ucb->gpio.parent = &ucb->dev; 5747655b2acSRussell King ucb->gpio.owner = THIS_MODULE; 575abe06082SRussell King ucb->gpio.base = pdata->gpio_base; 5769ca3dc80SThomas Kunze ucb->gpio.ngpio = 10; 5779ca3dc80SThomas Kunze ucb->gpio.set = ucb1x00_gpio_set; 5789ca3dc80SThomas Kunze ucb->gpio.get = ucb1x00_gpio_get; 5799ca3dc80SThomas Kunze ucb->gpio.direction_input = ucb1x00_gpio_direction_input; 5809ca3dc80SThomas Kunze ucb->gpio.direction_output = ucb1x00_gpio_direction_output; 581a3364409SRussell King ucb->gpio.to_irq = ucb1x00_to_irq; 5829ca3dc80SThomas Kunze ret = gpiochip_add(&ucb->gpio); 5839ca3dc80SThomas Kunze if (ret) 584f5ae587fSRussell King goto err_gpio_add; 5859ca3dc80SThomas Kunze } else 5869ca3dc80SThomas Kunze dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); 5879ca3dc80SThomas Kunze 58805c45ca9SRussell King mcp_set_drvdata(mcp, ucb); 58905c45ca9SRussell King 59033237616SRussell King if (pdata) 59133237616SRussell King device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup); 59233237616SRussell King 59305c45ca9SRussell King INIT_LIST_HEAD(&ucb->devs); 594a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 59565b539bbSRussell King list_add_tail(&ucb->node, &ucb1x00_devices); 59605c45ca9SRussell King list_for_each_entry(drv, &ucb1x00_drivers, node) { 59705c45ca9SRussell King ucb1x00_add_dev(ucb, drv); 59805c45ca9SRussell King } 599a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 6009ca3dc80SThomas Kunze 6012f7510c6SRussell King return ret; 60205c45ca9SRussell King 603f5ae587fSRussell King err_gpio_add: 604a3364409SRussell King irq_set_chained_handler(ucb->irq, NULL); 605a3364409SRussell King err_irq_alloc: 606a3364409SRussell King if (ucb->irq_base > 0) 607a3364409SRussell King irq_free_descs(ucb->irq_base, 16); 608f5ae587fSRussell King err_no_irq: 609f5ae587fSRussell King device_del(&ucb->dev); 610f5ae587fSRussell King err_dev_add: 611f5ae587fSRussell King put_device(&ucb->dev); 61205c45ca9SRussell King out: 6132f7510c6SRussell King if (pdata && pdata->reset) 6142f7510c6SRussell King pdata->reset(UCB_RST_PROBE_FAIL); 61505c45ca9SRussell King return ret; 61605c45ca9SRussell King } 61705c45ca9SRussell King 61805c45ca9SRussell King static void ucb1x00_remove(struct mcp *mcp) 61905c45ca9SRussell King { 6202f7510c6SRussell King struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; 62105c45ca9SRussell King struct ucb1x00 *ucb = mcp_get_drvdata(mcp); 62205c45ca9SRussell King struct list_head *l, *n; 62305c45ca9SRussell King 624a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 62505c45ca9SRussell King list_del(&ucb->node); 62605c45ca9SRussell King list_for_each_safe(l, n, &ucb->devs) { 62705c45ca9SRussell King struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, dev_node); 62805c45ca9SRussell King ucb1x00_remove_dev(dev); 62905c45ca9SRussell King } 630a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 63105c45ca9SRussell King 63288d5e520Sabdoulaye berthe if (ucb->gpio.base != -1) 63388d5e520Sabdoulaye berthe gpiochip_remove(&ucb->gpio); 6349ca3dc80SThomas Kunze 635a3364409SRussell King irq_set_chained_handler(ucb->irq, NULL); 636a3364409SRussell King irq_free_descs(ucb->irq_base, 16); 6370c55445fSTony Jones device_unregister(&ucb->dev); 6382f7510c6SRussell King 6392f7510c6SRussell King if (pdata && pdata->reset) 6402f7510c6SRussell King pdata->reset(UCB_RST_REMOVE); 64105c45ca9SRussell King } 64205c45ca9SRussell King 64305c45ca9SRussell King int ucb1x00_register_driver(struct ucb1x00_driver *drv) 64405c45ca9SRussell King { 64505c45ca9SRussell King struct ucb1x00 *ucb; 64605c45ca9SRussell King 64705c45ca9SRussell King INIT_LIST_HEAD(&drv->devs); 648a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 64965b539bbSRussell King list_add_tail(&drv->node, &ucb1x00_drivers); 65005c45ca9SRussell King list_for_each_entry(ucb, &ucb1x00_devices, node) { 65105c45ca9SRussell King ucb1x00_add_dev(ucb, drv); 65205c45ca9SRussell King } 653a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 65405c45ca9SRussell King return 0; 65505c45ca9SRussell King } 65605c45ca9SRussell King 65705c45ca9SRussell King void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) 65805c45ca9SRussell King { 65905c45ca9SRussell King struct list_head *n, *l; 66005c45ca9SRussell King 661a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 66205c45ca9SRussell King list_del(&drv->node); 66305c45ca9SRussell King list_for_each_safe(l, n, &drv->devs) { 66405c45ca9SRussell King struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, drv_node); 66505c45ca9SRussell King ucb1x00_remove_dev(dev); 66605c45ca9SRussell King } 667a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 66805c45ca9SRussell King } 66905c45ca9SRussell King 6709924713aSJingoo Han #ifdef CONFIG_PM_SLEEP 6715a09b712SRussell King static int ucb1x00_suspend(struct device *dev) 67205c45ca9SRussell King { 673334a41ceSJingoo Han struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); 6745a09b712SRussell King struct ucb1x00 *ucb = dev_get_drvdata(dev); 6755a09b712SRussell King struct ucb1x00_dev *udev; 67605c45ca9SRussell King 677a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 6785a09b712SRussell King list_for_each_entry(udev, &ucb->devs, dev_node) { 6795a09b712SRussell King if (udev->drv->suspend) 6805a09b712SRussell King udev->drv->suspend(udev); 68105c45ca9SRussell King } 682a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 68333237616SRussell King 68433237616SRussell King if (ucb->irq_wake) { 68533237616SRussell King unsigned long flags; 68633237616SRussell King 68733237616SRussell King raw_spin_lock_irqsave(&ucb->irq_lock, flags); 68833237616SRussell King ucb1x00_enable(ucb); 68933237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & 69033237616SRussell King ucb->irq_wake); 69133237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & 69233237616SRussell King ucb->irq_wake); 69333237616SRussell King ucb1x00_disable(ucb); 69433237616SRussell King raw_spin_unlock_irqrestore(&ucb->irq_lock, flags); 69533237616SRussell King 69633237616SRussell King enable_irq_wake(ucb->irq); 69733237616SRussell King } else if (pdata && pdata->reset) 69833237616SRussell King pdata->reset(UCB_RST_SUSPEND); 69933237616SRussell King 70005c45ca9SRussell King return 0; 70105c45ca9SRussell King } 70205c45ca9SRussell King 7035a09b712SRussell King static int ucb1x00_resume(struct device *dev) 70405c45ca9SRussell King { 705334a41ceSJingoo Han struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); 7065a09b712SRussell King struct ucb1x00 *ucb = dev_get_drvdata(dev); 7075a09b712SRussell King struct ucb1x00_dev *udev; 70805c45ca9SRussell King 70933237616SRussell King if (!ucb->irq_wake && pdata && pdata->reset) 71033237616SRussell King pdata->reset(UCB_RST_RESUME); 71133237616SRussell King 712ed442b67SRussell King ucb1x00_enable(ucb); 7132e95e51eSRussell King ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 7149ca3dc80SThomas Kunze ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); 71533237616SRussell King 71633237616SRussell King if (ucb->irq_wake) { 71733237616SRussell King unsigned long flags; 71833237616SRussell King 71933237616SRussell King raw_spin_lock_irqsave(&ucb->irq_lock, flags); 72033237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & 72133237616SRussell King ucb->irq_mask); 72233237616SRussell King ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & 72333237616SRussell King ucb->irq_mask); 72433237616SRussell King raw_spin_unlock_irqrestore(&ucb->irq_lock, flags); 72533237616SRussell King 72633237616SRussell King disable_irq_wake(ucb->irq); 72733237616SRussell King } 728ed442b67SRussell King ucb1x00_disable(ucb); 72933237616SRussell King 730a621aaedSArjan van de Ven mutex_lock(&ucb1x00_mutex); 7315a09b712SRussell King list_for_each_entry(udev, &ucb->devs, dev_node) { 7325a09b712SRussell King if (udev->drv->resume) 7335a09b712SRussell King udev->drv->resume(udev); 73405c45ca9SRussell King } 735a621aaedSArjan van de Ven mutex_unlock(&ucb1x00_mutex); 73605c45ca9SRussell King return 0; 73705c45ca9SRussell King } 7389924713aSJingoo Han #endif 73905c45ca9SRussell King 740507c133bSJingoo Han static SIMPLE_DEV_PM_OPS(ucb1x00_pm_ops, ucb1x00_suspend, ucb1x00_resume); 7415a09b712SRussell King 74205c45ca9SRussell King static struct mcp_driver ucb1x00_driver = { 74305c45ca9SRussell King .drv = { 74405c45ca9SRussell King .name = "ucb1x00", 745ddb1e04aSRussell King .owner = THIS_MODULE, 7465a09b712SRussell King .pm = &ucb1x00_pm_ops, 74705c45ca9SRussell King }, 74805c45ca9SRussell King .probe = ucb1x00_probe, 74905c45ca9SRussell King .remove = ucb1x00_remove, 75005c45ca9SRussell King }; 75105c45ca9SRussell King 75205c45ca9SRussell King static int __init ucb1x00_init(void) 75305c45ca9SRussell King { 75405c45ca9SRussell King int ret = class_register(&ucb1x00_class); 75505c45ca9SRussell King if (ret == 0) { 75605c45ca9SRussell King ret = mcp_driver_register(&ucb1x00_driver); 75705c45ca9SRussell King if (ret) 75805c45ca9SRussell King class_unregister(&ucb1x00_class); 75905c45ca9SRussell King } 76005c45ca9SRussell King return ret; 76105c45ca9SRussell King } 76205c45ca9SRussell King 76305c45ca9SRussell King static void __exit ucb1x00_exit(void) 76405c45ca9SRussell King { 76505c45ca9SRussell King mcp_driver_unregister(&ucb1x00_driver); 76605c45ca9SRussell King class_unregister(&ucb1x00_class); 76705c45ca9SRussell King } 76805c45ca9SRussell King 76905c45ca9SRussell King module_init(ucb1x00_init); 77005c45ca9SRussell King module_exit(ucb1x00_exit); 77105c45ca9SRussell King 77205c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_set_dir); 77305c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_write); 77405c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_io_read); 77505c45ca9SRussell King 77605c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_enable); 77705c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_read); 77805c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_adc_disable); 77905c45ca9SRussell King 78005c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_register_driver); 78105c45ca9SRussell King EXPORT_SYMBOL(ucb1x00_unregister_driver); 78205c45ca9SRussell King 783ddb1e04aSRussell King MODULE_ALIAS("mcp:ucb1x00"); 78405c45ca9SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); 78505c45ca9SRussell King MODULE_DESCRIPTION("UCB1x00 core driver"); 78605c45ca9SRussell King MODULE_LICENSE("GPL"); 787