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 <asm/irq.h> 23 #include <mach/hardware.h> 24 #include <asm/hardware/ssp.h> 25 26 #define TIMEOUT 100000 27 28 static 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 */ 54 int 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 */ 91 int 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 */ 118 int 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 */ 140 void 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 */ 150 void 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 */ 161 void 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 */ 175 void 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 */ 194 int 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 */ 223 void ssp_exit(void) 224 { 225 Ser4SSCR0 &= ~SSCR0_SSE; 226 227 free_irq(IRQ_Ser4SSP, NULL); 228 release_mem_region(__PREG(Ser4SSCR0), 0x18); 229 } 230 231 MODULE_AUTHOR("Russell King"); 232 MODULE_DESCRIPTION("SA11x0 SSP PIO driver"); 233 MODULE_LICENSE("GPL"); 234 235 EXPORT_SYMBOL(ssp_write_word); 236 EXPORT_SYMBOL(ssp_read_word); 237 EXPORT_SYMBOL(ssp_flush); 238 EXPORT_SYMBOL(ssp_enable); 239 EXPORT_SYMBOL(ssp_disable); 240 EXPORT_SYMBOL(ssp_save_state); 241 EXPORT_SYMBOL(ssp_restore_state); 242 EXPORT_SYMBOL(ssp_init); 243 EXPORT_SYMBOL(ssp_exit); 244