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