1/* 2 * linux/arch/arm/mach-pxa/ssp.c 3 * 4 * based on linux/arch/arm/mach-sa1100/ssp.c by Russell King 5 * 6 * Copyright (C) 2003 Russell King. 7 * Copyright (C) 2003 Wolfson Microelectronics PLC 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 * PXA2xx SSP driver. This provides the generic core for simple 14 * IO-based SSP applications and allows easy port setup for DMA access. 15 * 16 * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> 17 * 18 * Revision history: 19 * 22nd Aug 2003 Initial version. 20 * 20th Dec 2004 Added ssp_config for changing port config without 21 * closing the port. 22 * 4th Aug 2005 Added option to disable irq handler registration and 23 * cleaned up irq and clock detection. 24 */ 25 26#include <linux/module.h> 27#include <linux/kernel.h> 28#include <linux/sched.h> 29#include <linux/slab.h> 30#include <linux/errno.h> 31#include <linux/interrupt.h> 32#include <linux/ioport.h> 33#include <linux/init.h> 34#include <linux/mutex.h> 35#include <asm/io.h> 36#include <asm/irq.h> 37#include <asm/hardware.h> 38#include <asm/arch/ssp.h> 39#include <asm/arch/pxa-regs.h> 40 41#define PXA_SSP_PORTS 3 42 43#define TIMEOUT 100000 44 45struct ssp_info_ { 46 int irq; 47 u32 clock; 48}; 49 50/* 51 * SSP port clock and IRQ settings 52 */ 53static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { 54#if defined(CONFIG_PXA27x) 55 {IRQ_SSP, CKEN_SSP1}, 56 {IRQ_SSP2, CKEN_SSP2}, 57 {IRQ_SSP3, CKEN_SSP3}, 58#else 59 {IRQ_SSP, CKEN_SSP}, 60 {IRQ_NSSP, CKEN_NSSP}, 61 {IRQ_ASSP, CKEN_ASSP}, 62#endif 63}; 64 65static DEFINE_MUTEX(mutex); 66static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; 67 68static irqreturn_t ssp_interrupt(int irq, void *dev_id) 69{ 70 struct ssp_dev *dev = (struct ssp_dev*) dev_id; 71 unsigned int status = SSSR_P(dev->port); 72 73 SSSR_P(dev->port) = status; /* clear status bits */ 74 75 if (status & SSSR_ROR) 76 printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port); 77 78 if (status & SSSR_TUR) 79 printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port); 80 81 if (status & SSSR_BCE) 82 printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port); 83 84 return IRQ_HANDLED; 85} 86 87/** 88 * ssp_write_word - write a word to the SSP port 89 * @data: 32-bit, MSB justified data to write. 90 * 91 * Wait for a free entry in the SSP transmit FIFO, and write a data 92 * word to the SSP port. 93 * 94 * The caller is expected to perform the necessary locking. 95 * 96 * Returns: 97 * %-ETIMEDOUT timeout occurred 98 * 0 success 99 */ 100int ssp_write_word(struct ssp_dev *dev, u32 data) 101{ 102 int timeout = TIMEOUT; 103 104 while (!(SSSR_P(dev->port) & SSSR_TNF)) { 105 if (!--timeout) 106 return -ETIMEDOUT; 107 cpu_relax(); 108 } 109 110 SSDR_P(dev->port) = data; 111 112 return 0; 113} 114 115/** 116 * ssp_read_word - read a word from the SSP port 117 * 118 * Wait for a data word in the SSP receive FIFO, and return the 119 * received data. Data is LSB justified. 120 * 121 * Note: Currently, if data is not expected to be received, this 122 * function will wait for ever. 123 * 124 * The caller is expected to perform the necessary locking. 125 * 126 * Returns: 127 * %-ETIMEDOUT timeout occurred 128 * 32-bit data success 129 */ 130int ssp_read_word(struct ssp_dev *dev, u32 *data) 131{ 132 int timeout = TIMEOUT; 133 134 while (!(SSSR_P(dev->port) & SSSR_RNE)) { 135 if (!--timeout) 136 return -ETIMEDOUT; 137 cpu_relax(); 138 } 139 140 *data = SSDR_P(dev->port); 141 return 0; 142} 143 144/** 145 * ssp_flush - flush the transmit and receive FIFOs 146 * 147 * Wait for the SSP to idle, and ensure that the receive FIFO 148 * is empty. 149 * 150 * The caller is expected to perform the necessary locking. 151 */ 152int ssp_flush(struct ssp_dev *dev) 153{ 154 int timeout = TIMEOUT * 2; 155 156 do { 157 while (SSSR_P(dev->port) & SSSR_RNE) { 158 if (!--timeout) 159 return -ETIMEDOUT; 160 (void) SSDR_P(dev->port); 161 } 162 if (!--timeout) 163 return -ETIMEDOUT; 164 } while (SSSR_P(dev->port) & SSSR_BSY); 165 166 return 0; 167} 168 169/** 170 * ssp_enable - enable the SSP port 171 * 172 * Turn on the SSP port. 173 */ 174void ssp_enable(struct ssp_dev *dev) 175{ 176 SSCR0_P(dev->port) |= SSCR0_SSE; 177} 178 179/** 180 * ssp_disable - shut down the SSP port 181 * 182 * Turn off the SSP port, optionally powering it down. 183 */ 184void ssp_disable(struct ssp_dev *dev) 185{ 186 SSCR0_P(dev->port) &= ~SSCR0_SSE; 187} 188 189/** 190 * ssp_save_state - save the SSP configuration 191 * @ssp: pointer to structure to save SSP configuration 192 * 193 * Save the configured SSP state for suspend. 194 */ 195void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp) 196{ 197 ssp->cr0 = SSCR0_P(dev->port); 198 ssp->cr1 = SSCR1_P(dev->port); 199 ssp->to = SSTO_P(dev->port); 200 ssp->psp = SSPSP_P(dev->port); 201 202 SSCR0_P(dev->port) &= ~SSCR0_SSE; 203} 204 205/** 206 * ssp_restore_state - restore a previously saved SSP configuration 207 * @ssp: pointer to configuration saved by ssp_save_state 208 * 209 * Restore the SSP configuration saved previously by ssp_save_state. 210 */ 211void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp) 212{ 213 SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE; 214 215 SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE; 216 SSCR1_P(dev->port) = ssp->cr1; 217 SSTO_P(dev->port) = ssp->to; 218 SSPSP_P(dev->port) = ssp->psp; 219 220 SSCR0_P(dev->port) = ssp->cr0; 221} 222 223/** 224 * ssp_config - configure SSP port settings 225 * @mode: port operating mode 226 * @flags: port config flags 227 * @psp_flags: port PSP config flags 228 * @speed: port speed 229 * 230 * Port MUST be disabled by ssp_disable before making any config changes. 231 */ 232int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed) 233{ 234 dev->mode = mode; 235 dev->flags = flags; 236 dev->psp_flags = psp_flags; 237 dev->speed = speed; 238 239 /* set up port type, speed, port settings */ 240 SSCR0_P(dev->port) = (dev->speed | dev->mode); 241 SSCR1_P(dev->port) = dev->flags; 242 SSPSP_P(dev->port) = dev->psp_flags; 243 244 return 0; 245} 246 247/** 248 * ssp_init - setup the SSP port 249 * 250 * initialise and claim resources for the SSP port. 251 * 252 * Returns: 253 * %-ENODEV if the SSP port is unavailable 254 * %-EBUSY if the resources are already in use 255 * %0 on success 256 */ 257int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags) 258{ 259 int ret; 260 261 if (port > PXA_SSP_PORTS || port == 0) 262 return -ENODEV; 263 264 mutex_lock(&mutex); 265 if (use_count[port - 1]) { 266 mutex_unlock(&mutex); 267 return -EBUSY; 268 } 269 use_count[port - 1]++; 270 271 if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) { 272 use_count[port - 1]--; 273 mutex_unlock(&mutex); 274 return -EBUSY; 275 } 276 dev->port = port; 277 278 /* do we need to get irq */ 279 if (!(init_flags & SSP_NO_IRQ)) { 280 ret = request_irq(ssp_info[port-1].irq, ssp_interrupt, 281 0, "SSP", dev); 282 if (ret) 283 goto out_region; 284 dev->irq = ssp_info[port-1].irq; 285 } else 286 dev->irq = 0; 287 288 /* turn on SSP port clock */ 289 pxa_set_cken(ssp_info[port-1].clock, 1); 290 mutex_unlock(&mutex); 291 return 0; 292 293out_region: 294 release_mem_region(__PREG(SSCR0_P(port)), 0x2c); 295 use_count[port - 1]--; 296 mutex_unlock(&mutex); 297 return ret; 298} 299 300/** 301 * ssp_exit - undo the effects of ssp_init 302 * 303 * release and free resources for the SSP port. 304 */ 305void ssp_exit(struct ssp_dev *dev) 306{ 307 mutex_lock(&mutex); 308 SSCR0_P(dev->port) &= ~SSCR0_SSE; 309 310 if (dev->port > PXA_SSP_PORTS || dev->port == 0) { 311 printk(KERN_WARNING "SSP: tried to close invalid port\n"); 312 return; 313 } 314 315 pxa_set_cken(ssp_info[dev->port-1].clock, 0); 316 if (dev->irq) 317 free_irq(dev->irq, dev); 318 release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); 319 use_count[dev->port - 1]--; 320 mutex_unlock(&mutex); 321} 322 323EXPORT_SYMBOL(ssp_write_word); 324EXPORT_SYMBOL(ssp_read_word); 325EXPORT_SYMBOL(ssp_flush); 326EXPORT_SYMBOL(ssp_enable); 327EXPORT_SYMBOL(ssp_disable); 328EXPORT_SYMBOL(ssp_save_state); 329EXPORT_SYMBOL(ssp_restore_state); 330EXPORT_SYMBOL(ssp_init); 331EXPORT_SYMBOL(ssp_exit); 332EXPORT_SYMBOL(ssp_config); 333 334MODULE_DESCRIPTION("PXA SSP driver"); 335MODULE_AUTHOR("Liam Girdwood"); 336MODULE_LICENSE("GPL"); 337