diff options
| author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-09-11 05:26:31 -0400 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-09-11 05:26:31 -0400 |
| commit | 05c45ca9aa4ec57e8e22341633c7a98cc879423d (patch) | |
| tree | d741028790d6f0b3ede6eb7e4e0632259d5aa4d3 | |
| parent | 2f79f458d2ab4a77f1b9df8d0041e51ce085d7c0 (diff) | |
[MFD] Add code UCB1200/UCB1300 device support
Add the core device support code for the Philips UCB1200 and
UCB1300 devices. Also includes the following from Pavel:
This fixes u32 vs. pm_message_t confusion and uses cleaner
try_to_freeze() [fixing compilation as a side-effect on newer
kernels.]
Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
| -rw-r--r-- | drivers/mfd/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mfd/ucb1x00-core.c | 665 | ||||
| -rw-r--r-- | drivers/mfd/ucb1x00.h | 256 |
4 files changed, 927 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1588a59e37..1f8563bde4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -13,4 +13,9 @@ config MCP_SA11X0 | |||
| 13 | depends on ARCH_SA1100 | 13 | depends on ARCH_SA1100 |
| 14 | select MCP | 14 | select MCP |
| 15 | 15 | ||
| 16 | # Chip drivers | ||
| 17 | config MCP_UCB1200 | ||
| 18 | tristate "Support for UCB1200 / UCB1300" | ||
| 19 | depends on MCP | ||
| 20 | |||
| 16 | endmenu | 21 | endmenu |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 98bdd6a421..90815b2840 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_MCP) += mcp-core.o | 5 | obj-$(CONFIG_MCP) += mcp-core.o |
| 6 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o | 6 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o |
| 7 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o | ||
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c new file mode 100644 index 0000000000..10f6ce1bc0 --- /dev/null +++ b/drivers/mfd/ucb1x00-core.c | |||
| @@ -0,0 +1,665 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/mfd/ucb1x00-core.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 Russell King, All Rights Reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License. | ||
| 9 | * | ||
| 10 | * The UCB1x00 core driver provides basic services for handling IO, | ||
| 11 | * the ADC, interrupts, and accessing registers. It is designed | ||
| 12 | * such that everything goes through this layer, thereby providing | ||
| 13 | * a consistent locking methodology, as well as allowing the drivers | ||
| 14 | * to be used on other non-MCP-enabled hardware platforms. | ||
| 15 | * | ||
| 16 | * Note that all locks are private to this file. Nothing else may | ||
| 17 | * touch them. | ||
| 18 | */ | ||
| 19 | #include <linux/config.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/interrupt.h> | ||
| 26 | #include <linux/device.h> | ||
| 27 | |||
| 28 | #include <asm/dma.h> | ||
| 29 | #include <asm/hardware.h> | ||
| 30 | #include <asm/irq.h> | ||
| 31 | |||
| 32 | #include "ucb1x00.h" | ||
| 33 | |||
| 34 | static DECLARE_MUTEX(ucb1x00_sem); | ||
| 35 | static LIST_HEAD(ucb1x00_drivers); | ||
| 36 | static LIST_HEAD(ucb1x00_devices); | ||
| 37 | |||
| 38 | /** | ||
| 39 | * ucb1x00_io_set_dir - set IO direction | ||
| 40 | * @ucb: UCB1x00 structure describing chip | ||
| 41 | * @in: bitfield of IO pins to be set as inputs | ||
| 42 | * @out: bitfield of IO pins to be set as outputs | ||
| 43 | * | ||
| 44 | * Set the IO direction of the ten general purpose IO pins on | ||
| 45 | * the UCB1x00 chip. The @in bitfield has priority over the | ||
| 46 | * @out bitfield, in that if you specify a pin as both input | ||
| 47 | * and output, it will end up as an input. | ||
| 48 | * | ||
| 49 | * ucb1x00_enable must have been called to enable the comms | ||
| 50 | * before using this function. | ||
| 51 | * | ||
| 52 | * This function takes a spinlock, disabling interrupts. | ||
| 53 | */ | ||
| 54 | void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out) | ||
| 55 | { | ||
| 56 | unsigned long flags; | ||
| 57 | |||
| 58 | spin_lock_irqsave(&ucb->io_lock, flags); | ||
| 59 | ucb->io_dir |= out; | ||
| 60 | ucb->io_dir &= ~in; | ||
| 61 | |||
| 62 | ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); | ||
| 63 | spin_unlock_irqrestore(&ucb->io_lock, flags); | ||
| 64 | } | ||
| 65 | |||
| 66 | /** | ||
| 67 | * ucb1x00_io_write - set or clear IO outputs | ||
| 68 | * @ucb: UCB1x00 structure describing chip | ||
| 69 | * @set: bitfield of IO pins to set to logic '1' | ||
| 70 | * @clear: bitfield of IO pins to set to logic '0' | ||
| 71 | * | ||
| 72 | * Set the IO output state of the specified IO pins. The value | ||
| 73 | * is retained if the pins are subsequently configured as inputs. | ||
| 74 | * The @clear bitfield has priority over the @set bitfield - | ||
| 75 | * outputs will be cleared. | ||
| 76 | * | ||
| 77 | * ucb1x00_enable must have been called to enable the comms | ||
| 78 | * before using this function. | ||
| 79 | * | ||
| 80 | * This function takes a spinlock, disabling interrupts. | ||
| 81 | */ | ||
| 82 | void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear) | ||
| 83 | { | ||
| 84 | unsigned long flags; | ||
| 85 | |||
| 86 | spin_lock_irqsave(&ucb->io_lock, flags); | ||
| 87 | ucb->io_out |= set; | ||
| 88 | ucb->io_out &= ~clear; | ||
| 89 | |||
| 90 | ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); | ||
| 91 | spin_unlock_irqrestore(&ucb->io_lock, flags); | ||
| 92 | } | ||
| 93 | |||
| 94 | /** | ||
| 95 | * ucb1x00_io_read - read the current state of the IO pins | ||
| 96 | * @ucb: UCB1x00 structure describing chip | ||
| 97 | * | ||
| 98 | * Return a bitfield describing the logic state of the ten | ||
| 99 | * general purpose IO pins. | ||
| 100 | * | ||
| 101 | * ucb1x00_enable must have been called to enable the comms | ||
| 102 | * before using this function. | ||
| 103 | * | ||
| 104 | * This function does not take any semaphores or spinlocks. | ||
| 105 | */ | ||
| 106 | unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) | ||
| 107 | { | ||
| 108 | return ucb1x00_reg_read(ucb, UCB_IO_DATA); | ||
| 109 | } | ||
| 110 | |||
| 111 | /* | ||
| 112 | * UCB1300 data sheet says we must: | ||
| 113 | * 1. enable ADC => 5us (including reference startup time) | ||
| 114 | * 2. select input => 51*tsibclk => 4.3us | ||
| 115 | * 3. start conversion => 102*tsibclk => 8.5us | ||
| 116 | * (tsibclk = 1/11981000) | ||
| 117 | * Period between SIB 128-bit frames = 10.7us | ||
| 118 | */ | ||
| 119 | |||
| 120 | /** | ||
| 121 | * ucb1x00_adc_enable - enable the ADC converter | ||
| 122 | * @ucb: UCB1x00 structure describing chip | ||
| 123 | * | ||
| 124 | * Enable the ucb1x00 and ADC converter on the UCB1x00 for use. | ||
| 125 | * Any code wishing to use the ADC converter must call this | ||
| 126 | * function prior to using it. | ||
| 127 | * | ||
| 128 | * This function takes the ADC semaphore to prevent two or more | ||
| 129 | * concurrent uses, and therefore may sleep. As a result, it | ||
| 130 | * can only be called from process context, not interrupt | ||
| 131 | * context. | ||
| 132 | * | ||
| 133 | * You should release the ADC as soon as possible using | ||
| 134 | * ucb1x00_adc_disable. | ||
| 135 | */ | ||
| 136 | void ucb1x00_adc_enable(struct ucb1x00 *ucb) | ||
| 137 | { | ||
| 138 | down(&ucb->adc_sem); | ||
| 139 | |||
| 140 | ucb->adc_cr |= UCB_ADC_ENA; | ||
| 141 | |||
| 142 | ucb1x00_enable(ucb); | ||
| 143 | ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * ucb1x00_adc_read - read the specified ADC channel | ||
| 148 | * @ucb: UCB1x00 structure describing chip | ||
| 149 | * @adc_channel: ADC channel mask | ||
| 150 | * @sync: wait for syncronisation pulse. | ||
| 151 | * | ||
| 152 | * Start an ADC conversion and wait for the result. Note that | ||
| 153 | * synchronised ADC conversions (via the ADCSYNC pin) must wait | ||
| 154 | * until the trigger is asserted and the conversion is finished. | ||
| 155 | * | ||
| 156 | * This function currently spins waiting for the conversion to | ||
| 157 | * complete (2 frames max without sync). | ||
| 158 | * | ||
| 159 | * If called for a synchronised ADC conversion, it may sleep | ||
| 160 | * with the ADC semaphore held. | ||
| 161 | */ | ||
| 162 | unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) | ||
| 163 | { | ||
| 164 | unsigned int val; | ||
| 165 | |||
| 166 | if (sync) | ||
| 167 | adc_channel |= UCB_ADC_SYNC_ENA; | ||
| 168 | |||
| 169 | ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel); | ||
| 170 | ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START); | ||
| 171 | |||
| 172 | for (;;) { | ||
| 173 | val = ucb1x00_reg_read(ucb, UCB_ADC_DATA); | ||
| 174 | if (val & UCB_ADC_DAT_VAL) | ||
| 175 | break; | ||
| 176 | /* yield to other processes */ | ||
| 177 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 178 | schedule_timeout(1); | ||
| 179 | } | ||
| 180 | |||
| 181 | return UCB_ADC_DAT(val); | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * ucb1x00_adc_disable - disable the ADC converter | ||
| 186 | * @ucb: UCB1x00 structure describing chip | ||
| 187 | * | ||
| 188 | * Disable the ADC converter and release the ADC semaphore. | ||
| 189 | */ | ||
| 190 | void ucb1x00_adc_disable(struct ucb1x00 *ucb) | ||
| 191 | { | ||
| 192 | ucb->adc_cr &= ~UCB_ADC_ENA; | ||
| 193 | ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); | ||
| 194 | ucb1x00_disable(ucb); | ||
| 195 | |||
