1/* 2 * linux/arch/arm/mach-sa1100/ssp.c 3 * 4 * Copyright (C) 2003 Russell King. 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 version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Generic SSP driver. This provides the generic core for simple 11 * IO-based SSP applications. 12 */ 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/sched.h> 16#include <linux/errno.h> 17#include <linux/interrupt.h> 18#include <linux/ioport.h> 19#include <linux/init.h> 20#include <linux/io.h> 21 22#include <mach/hardware.h> 23#include <mach/irqs.h> 24#include <asm/hardware/ssp.h> 25 26#define TIMEOUT 100000 27 28static irqreturn_t ssp_interrupt(int irq, void *dev_id) 29{ 30 unsigned int status = Ser4SSSR; 31 32 if (status & SSSR_ROR) 33 printk(KERN_WARNING "SSP: receiver overrun\n"); 34 35 Ser4SSSR = SSSR_ROR; 36 37 return status ? IRQ_HANDLED : IRQ_NONE; 38} 39 40/** 41 * ssp_write_word - write a word to the SSP port 42 * @data: 16-bit, MSB justified data to write. 43 * 44 * Wait for a free entry in the SSP transmit FIFO, and write a data 45 * word to the SSP port. Wait for the SSP port to start sending 46 * the data. 47 * 48 * The caller is expected to perform the necessary locking. 49 * 50 * Returns: 51 * %-ETIMEDOUT timeout occurred 52 * 0 success 53 */ 54int ssp_write_word(u16 data) 55{ 56 int timeout = TIMEOUT; 57 58 while (!(Ser4SSSR & SSSR_TNF)) { 59 if (!--timeout) 60 return -ETIMEDOUT; 61 cpu_relax(); 62 } 63 64 Ser4SSDR = data; 65 66 timeout = TIMEOUT; 67 while (!(Ser4SSSR & SSSR_BSY)) { 68 if (!--timeout) 69 return -ETIMEDOUT; 70 cpu_relax(); 71 } 72 73 return 0; 74} 75 76/** 77 * ssp_read_word - read a word from the SSP port 78 * 79 * Wait for a data word in the SSP receive FIFO, and return the 80 * received data. Data is LSB justified. 81 * 82 * Note: Currently, if data is not expected to be received, this 83 * function will wait for ever. 84 * 85 * The caller is expected to perform the necessary locking. 86 * 87 * Returns: 88 * %-ETIMEDOUT timeout occurred 89 * 16-bit data success 90 */ 91int ssp_read_word(u16 *data) 92{ 93 int timeout = TIMEOUT; 94 95 while (!(Ser4SSSR & SSSR_RNE)) { 96 if (!--timeout) 97 return -ETIMEDOUT; 98 cpu_relax(); 99 } 100 101 *data = (u16)Ser4SSDR; 102 103 return 0; 104} 105 106/** 107 * ssp_flush - flush the transmit and receive FIFOs 108 * 109 * Wait for the SSP to idle, and ensure that the receive FIFO 110 * is empty. 111 * 112 * The caller is expected to perform the necessary locking. 113 * 114 * Returns: 115 * %-ETIMEDOUT timeout occurred 116 * 0 success 117 */ 118int ssp_flush(void) 119{ 120 int timeout = TIMEOUT * 2; 121 122 do { 123 while (Ser4SSSR & SSSR_RNE) { 124 if (!--timeout) 125 return -ETIMEDOUT; 126 (void) Ser4SSDR; 127 } 128 if (!--timeout) 129 return -ETIMEDOUT; 130 } while (Ser4SSSR & SSSR_BSY); 131 132 return 0; 133} 134 135/** 136 * ssp_enable - enable the SSP port 137 * 138 * Turn on the SSP port. 139 */ 140void ssp_enable(void) 141{ 142 Ser4SSCR0 |= SSCR0_SSE; 143} 144 145/** 146 * ssp_disable - shut down the SSP port 147 * 148 * Turn off the SSP port, optionally powering it down. 149 */ 150void ssp_disable(void) 151{ 152 Ser4SSCR0 &= ~SSCR0_SSE; 153} 154 155/** 156 * ssp_save_state - save the SSP configuration 157 * @ssp: pointer to structure to save SSP configuration 158 * 159 * Save the configured SSP state for suspend. 160 */ 161void ssp_save_state(struct ssp_state *ssp) 162{ 163 ssp->cr0 = Ser4SSCR0; 164 ssp->cr1 = Ser4SSCR1; 165 166 Ser4SSCR0 &= ~SSCR0_SSE; 167} 168 169/** 170 * ssp_restore_state - restore a previously saved SSP configuration 171 * @ssp: pointer to configuration saved by ssp_save_state 172 * 173 * Restore the SSP configuration saved previously by ssp_save_state. 174 */ 175void ssp_restore_state(struct ssp_state *ssp) 176{ 177 Ser4SSSR = SSSR_ROR; 178 179 Ser4SSCR0 = ssp->cr0 & ~SSCR0_SSE; 180 Ser4SSCR1 = ssp->cr1; 181 Ser4SSCR0 = ssp->cr0; 182} 183 184/** 185 * ssp_init - setup the SSP port 186 * 187 * initialise and claim resources for the SSP port. 188 * 189 * Returns: 190 * %-ENODEV if the SSP port is unavailable 191 * %-EBUSY if the resources are already in use 192 * %0 on success 193 */ 194int ssp_init(void) 195{ 196 int ret; 197 198 if (!(PPAR & PPAR_SPR) && (Ser4MCCR0 & MCCR0_MCE)) 199 return -ENODEV; 200 201 if (!request_mem_region(__PREG(Ser4SSCR0), 0x18, "SSP")) { 202 return -EBUSY; 203 } 204 205 Ser4SSSR = SSSR_ROR; 206 207 ret = request_irq(IRQ_Ser4SSP, ssp_interrupt, 0, "SSP", NULL); 208 if (ret) 209 goto out_region; 210 211 return 0; 212 213 out_region: 214 release_mem_region(__PREG(Ser4SSCR0), 0x18); 215 return ret; 216} 217 218/** 219 * ssp_exit - undo the effects of ssp_init 220 * 221 * release and free resources for the SSP port. 222 */ 223void ssp_exit(void) 224{ 225 Ser4SSCR0 &= ~SSCR0_SSE; 226 227 free_irq(IRQ_Ser4SSP, NULL); 228 release_mem_region(__PREG(Ser4SSCR0), 0x18); 229} 230 231MODULE_AUTHOR("Russell King"); 232MODULE_DESCRIPTION("SA11x0 SSP PIO driver"); 233MODULE_LICENSE("GPL"); 234 235EXPORT_SYMBOL(ssp_write_word); 236EXPORT_SYMBOL(ssp_read_word); 237EXPORT_SYMBOL(ssp_flush); 238EXPORT_SYMBOL(ssp_enable); 239EXPORT_SYMBOL(ssp_disable); 240EXPORT_SYMBOL(ssp_save_state); 241EXPORT_SYMBOL(ssp_restore_state); 242EXPORT_SYMBOL(ssp_init); 243EXPORT_SYMBOL(ssp_exit); 244