tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / spi / sprd_spi.c
1 #include <asm/arch/sci_types.h>\r
2 #include <asm/arch/os_api.h>\r
3 #include <asm/arch/arm_reg.h>\r
4 #include <asm/arch/sprd_reg_base.h>\r
5 #include <asm/arch/sprd_reg_ahb.h>\r
6 #include <asm/arch/sprd_reg_global.h>\r
7 #include <asm/arch/sprd_spi.h>\r
8 #if defined(CONFIG_SC8830) || defined(CONFIG_SC9630)\r
9 #define SPI2_BASE               CTL_BASE_SPI2\r
10 #else\r
11 #define SPI2_BASE               0x4e006000\r
12 #endif\r
13 #define SPI_USED_BASE SPI2_BASE\r
14 \r
15 \r
16 /**---------------------------------------------------------------------------*\r
17  **                         Globle Variable                                  *\r
18  **---------------------------------------------------------------------------*/\r
19 \r
20 //endian switch mode\r
21 typedef enum\r
22 {\r
23         ENDIAN_SWITCH_NONE    = 0x00,    //  2'b00: 0xABCD => 0xABCD\r
24         ENDIAN_SWITCH_ALL     =0x01,     //  2'b01: 0xABCD => 0xDCBA\r
25         ENDIAN_SWITCH_MODE0   =0x02 ,    //  2'b01: 0xABCD => 0xBADC\r
26         ENDIAN_SWITCH_MODE1   = 0x03 ,   //  2'b01: 0xABCD => 0xCDAB\r
27         ENDIAN_SWITCH_MAX\r
28 } DMA_ENDIANSWITCH_E ;  //should be added to dma_hal_new.h\r
29 //data width\r
30 typedef enum DMA_DATAWIDTH\r
31 {\r
32         DMA_DATAWIDTH_BYTE = 0,\r
33         DMA_DATAWIDTH_HALFWORD,\r
34         DMA_DATAWIDTH_WORD,\r
35         DMA_DATAWIDTH_MAX\r
36 }  DMA_DATAWIDTH_E;\r
37 //request mode\r
38 typedef enum DMA_CHN_REQMODE\r
39 {\r
40         DMA_CHN_REQMODE_NORMAL = 0,\r
41         DMA_CHN_REQMODE_TRASACTION,\r
42         DMA_CHN_REQMODE_LIST,\r
43         DMA_CHN_REQMODE_INFINITE,\r
44         DMA_CHN_REQMODE_MAX\r
45 } DMA_CHN_REQMODE_E;\r
46 \r
47 \r
48 typedef enum LCM_DMA_RETURN_E\r
49 {\r
50         LCM_ERR_ID    = 0,\r
51         LCM_ERR_BUSWIDTH =1,   //only support:8-bit,16-bit 80_sys_bus\r
52         LCM_ERR_SRCADDR =2,    //not HalfWORD_align\r
53         LCM_ERR_ENDIAN\r
54 } LCM_DMA_RETURN_E;       //SHOULD define in lcd.h\r
55 \r
56 #define GEN0_SPI2_EN    1\r
57 \r
58 \r
59 /**---------------------------------------------------------------------------*\r
60  **                         Function Define                                    *\r
61  **---------------------------------------------------------------------------*/\r
62 PUBLIC void SPI_Enable( uint32 spi_id, BOOLEAN is_en)\r
63 {\r
64         if(is_en)\r
65         {\r
66                 switch(spi_id)\r
67                 {\r
68 #if defined(CONFIG_SC8830) || defined(CONFIG_SC9630)\r
69                                 //to do\r
70 #else\r
71                         case 0:\r
72                                 *(volatile uint32 *)GR_GEN0 |= ( 1 << GEN0_SPI0_EN);\r
73                                 break;\r
74                         case 1:\r
75                                 *(volatile uint32 *)GR_GEN0 |= ( 1 << GEN0_SPI1_EN);\r
76                                 break;\r
77                         case 2: \r
78                                 *(volatile uint32 *)GR_GEN0 |= ( 1 << GEN0_SPI2_EN);\r
79                                 break;\r
80                         default:\r
81                                 break;\r
82 #endif\r
83                 }\r
84         }\r
85         else\r
86         {\r
87 \r
88         }\r
89 \r
90 }\r
91 \r
92 PUBLIC void SPI_Reset( uint32 spi_id, uint32 ms)\r
93 {\r
94         uint32 i = 0;\r
95 #if defined(CONFIG_SC8830) || defined(CONFIG_SC9630)\r
96 \r
97 #else\r
98         if(spi_id == 0)\r
99         {\r
100                 *(volatile uint32 *)GR_SOFT_RST |= (1 << 14);\r
101                 for (i=0; i<0x100; i++);\r
102                 *(volatile uint32 *)GR_SOFT_RST &=~(1 << 14);        \r
103         }\r
104         else if(spi_id == 1)\r
105         {\r
106                 *(volatile uint32 *)GR_SOFT_RST |= (1 << 15);\r
107                 for (i=0; i<0x100; i++);\r
108                 *(volatile uint32 *)GR_SOFT_RST &=~(1 << 15);\r
109         }\r
110         else if(spi_id == 2)\r
111         {\r
112                 *(volatile uint32 *)GR_SOFT_RST |= (1 << 31);\r
113                 for (i=0; i<0x100; i++);\r
114                 *(volatile uint32 *)GR_SOFT_RST &=~(1 << 31);\r
115         }\r
116 #endif\r
117 }\r
118 \r
119 \r
120 LOCAL void SPI_PinConfig(void)\r
121 {\r
122 }\r
123 \r
124 \r
125 // The dividend is clk_spiX_div[1:0] + 1\r
126 PUBLIC void SPI_ClkSetting(uint32 spi_id, uint32 clk_src, uint32 clk_div)\r
127 {\r
128         //clk_spi0_sel: [3:2]---->2'b:00-78M 01-26M,01-104M,11-48M,\r
129         //clk_spi0_div: [5:4]---->div,  clk/(div+1)\r
130 #if defined(CONFIG_SC8830) || defined(CONFIG_SC9630)\r
131 \r
132 #else\r
133         if(spi_id == 0)\r
134         {\r
135                 *(volatile uint32 *) GR_CLK_DLY |= (clk_src&3)<<26;\r
136                 *(volatile uint32 *) GR_GEN2   |= (clk_div&7)<<21;\r
137         } else if(spi_id == 1){\r
138                 *(volatile uint32 *) GR_CLK_DLY |= (clk_src&3)<<30;\r
139                 *(volatile uint32 *) GR_GEN2   |= (clk_div&7)<<11;    \r
140         } else if(spi_id == 2){\r
141                 *(volatile uint32 *) GR_GEN3 |= (clk_src&3)<<3;\r
142                 *(volatile uint32 *) GR_GEN3   |= (clk_div&7)<<5;    \r
143         }\r
144 #endif\r
145 }\r
146 \r
147 \r
148 #define SPI_SEL_CS_SHIFT 8\r
149 #define SPI_SEL_CS_MASK (0x0F<<SPI_SEL_CS_SHIFT)\r
150 PUBLIC void SPI_SetCsLow( uint32 spi_sel_csx , BOOLEAN is_low)\r
151 {\r
152         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T*)(SPI_USED_BASE);\r
153         uint32 temp;\r
154 \r
155         if(is_low)     {\r
156                 //spi_ctl0[11:8]:cs3<->cs0 chip select, 0-selected;1-none\r
157                 spi_ctr_ptr->ctl0 &= ~(SPI_SEL_CS_MASK); \r
158                 spi_ctr_ptr->ctl0 &= ~((1<<spi_sel_csx)<<SPI_SEL_CS_SHIFT); \r
159         }\r
160         else\r
161         {\r
162                 //spi_ctl0[11:8]:cs3<->cs0 chip select, 0-selected;1-none\r
163                 spi_ctr_ptr->ctl0 |= ((1<<spi_sel_csx)<<SPI_SEL_CS_SHIFT); \r
164         }\r
165 }\r
166 \r
167 #define SPI_CD_MASK  BIT_15\r
168 PUBLIC void SPI_SetCd( uint32 cd)\r
169 {\r
170         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T*)(SPI_USED_BASE);\r
171 \r
172         //0-command;1-data\r
173         if(cd == 0)\r
174                 spi_ctr_ptr->ctl8 &= ~(SPI_CD_MASK);  \r
175         else\r
176                 spi_ctr_ptr->ctl8 |= (SPI_CD_MASK);  \r
177 }\r
178 \r
179 // USE spi interface to write cmd/data to the lcm\r
180 // pay attention to the data_format\r
181 typedef enum data_width\r
182 {\r
183         DATA_WIDTH_7bit =7,\r
184         DATA_WIDTH_8bit =8,\r
185         DATA_WIDTH_9bit =9,\r
186         DATA_WIDTH_10bit=10,\r
187         DATA_WIDTH_11bit=11,\r
188         DATA_WIDTH_12bit=12,\r
189 }  SPI_DATA_WIDTH;\r
190 \r
191 // Set spi work mode for LCM with spi interface\r
192 #define SPI_MODE_SHIFT    3 //[5:3]\r
193 #define SPI_MODE_MASK     (0x07<<SPI_MODE_SHIFT)\r
194 PUBLIC void SPI_SetSpiMode(uint32 spi_mode)\r
195 {\r
196         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
197         uint32 temp = spi_ctr_ptr->ctl7;\r
198 \r
199         temp &= ~SPI_MODE_MASK;\r
200         temp |= (spi_mode<<SPI_MODE_SHIFT);\r
201 \r
202         spi_ctr_ptr->ctl7 = temp;\r
203 }\r
204 \r
205 // Transmit data bit number:spi_ctl0[6:2] \r
206 PUBLIC void  SPI_SetDatawidth(uint32 datawidth)\r
207 {\r
208         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
209         uint32 temp = spi_ctr_ptr->ctl0;\r
210 \r
211         if( 32 == datawidth )\r
212         {\r
213                 spi_ctr_ptr->ctl0 &= ~0x7C;  //  [6:2]\r
214                 return;\r
215         }\r
216 \r
217         temp &= ~0x0000007C;  //mask\r
218         temp |= (datawidth<<2);\r
219 \r
220         spi_ctr_ptr->ctl0 = temp;\r
221 }\r
222 \r
223 #define TX_MAX_LEN_MASK     0xFFFFF\r
224 #define TX_DUMY_LEN_MASK    0x3F    //[09:04]\r
225 #define TX_DATA_LEN_H_MASK  0x0F    //[03:00]\r
226 #define TX_DATA_LEN_L_MASK  0xFFFF  //[15:00]\r
227 /*****************************************************************************/\r
228 //  Description:  Set rxt data length with dummy_len\r
229 //  Author     :  lichd\r
230 //    Note       :  the unit is identical with datawidth you set\r
231 /*****************************************************************************/ \r
232 PUBLIC void SPI_SetTxLen(uint32 data_len, uint32 dummy_bitlen)\r
233 {\r
234         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
235         uint32 ctl8 = spi_ctr_ptr->ctl8;\r
236         uint32 ctl9 = spi_ctr_ptr->ctl9;\r
237 \r
238         data_len &= TX_MAX_LEN_MASK;\r
239 \r
240         ctl8 &= ~((TX_DUMY_LEN_MASK<<4) | TX_DATA_LEN_H_MASK);\r
241         ctl9 &= ~( TX_DATA_LEN_L_MASK );\r
242 \r
243         // set dummy_bitlen in bit[9:4] and data_len[19:16] in bit[3:0]\r
244         spi_ctr_ptr->ctl8 = (ctl8 | (dummy_bitlen<<4) | (data_len>>16));\r
245         // set data_len[15:00]\r
246         spi_ctr_ptr->ctl9 = (ctl9 | (data_len&0xFFFF));\r
247 }\r
248 \r
249 \r
250 #define RX_MAX_LEN_MASK     0xFFFFFF\r
251 #define RX_DUMY_LEN_MASK    0x3F    //[09:04]\r
252 #define RX_DATA_LEN_H_MASK  0x0F    //[03:00]\r
253 #define RX_DATA_LEN_L_MASK  0xFFFF  //[15:00]\r
254 /*****************************************************************************/\r
255 //  Description:  Set rxt data length with dummy_len\r
256 //  Author     :  lichd\r
257 //    Note       :  the unit is identical with datawidth you set\r
258 /*****************************************************************************/ \r
259 PUBLIC void SPI_SetRxLen(uint32 data_len, uint32 dummy_bitlen)\r
260 {\r
261         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
262         uint32 ctl10 = spi_ctr_ptr->ctl10;\r
263         uint32 ctl11 = spi_ctr_ptr->ctl11;\r
264 \r
265         data_len &= RX_MAX_LEN_MASK;\r
266 \r
267         ctl10 &= ~((RX_DUMY_LEN_MASK<<4) | RX_DATA_LEN_H_MASK);\r
268         ctl11 &= ~( RX_DATA_LEN_L_MASK );\r
269 \r
270         // set dummy_bitlen in bit[9:4] and data_len[19:16] in bit[3:0]\r
271         spi_ctr_ptr->ctl10 = (ctl10 | (dummy_bitlen<<4) | (data_len>>16));\r
272         // set data_len[15:00]\r
273         spi_ctr_ptr->ctl11 = (ctl11 | (data_len&0xFFFF));\r
274 \r
275         /* in SPIMODE_3WIRE_9BIT_SDI ,DO\r
276         the tx len has to set 0 to generate 8 clk, or generate 9clk */\r
277         if(0x10==(spi_ctr_ptr->ctl7&(0x7 << 3))){\r
278                 spi_ctr_ptr->ctl8 &= 0xfff0;\r
279                 spi_ctr_ptr->ctl9 &= 0x0;\r
280                 }\r
281 }\r
282 \r
283 // Request txt trans before send data\r
284 #define SW_RX_REQ_MASK BIT_0\r
285 #define SW_TX_REQ_MASK BIT_1\r
286 PUBLIC void SPI_TxReq( void )\r
287 {\r
288         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
289 \r
290         spi_ctr_ptr->ctl12 |= SW_TX_REQ_MASK;\r
291 }\r
292 \r
293 PUBLIC void SPI_RxReq( void )\r
294 {\r
295         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
296 \r
297         spi_ctr_ptr->ctl12 |= SW_RX_REQ_MASK;\r
298 }\r
299 \r
300 /*****************************************************************************/\r
301 //  Description:      To enable or disable DMA depending on parameter(is_enable)\r
302 //  Author:         @Vine.Yuan 2010.5.10\r
303 //    Note:\r
304 /*****************************************************************************/ \r
305 PUBLIC BOOLEAN SPI_EnableDMA(uint32 spi_index,BOOLEAN is_enable)\r
306 {\r
307         volatile SPI_CTL_REG_T* spi_ctl;\r
308 \r
309         spi_ctl = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE+0x3000*spi_index); \r
310 \r
311         if (is_enable)\r
312         {\r
313                 spi_ctl->ctl2 |= BIT_6;\r
314         }\r
315         else\r
316         {\r
317                 spi_ctl->ctl2 &= ~BIT_6;\r
318         }\r
319 \r
320         //spi_ctl->ctl7 |= (BIT_7 | BIT_8);\r
321         spi_ctl->ctl7 |= (BIT_7);\r
322 \r
323         return SCI_TRUE;\r
324 }\r
325 \r
326 #define SPI_DMA_TIME_OUT        0x80000\r
327 #define BURST_SIZE              16\r
328 #define BURST_SIZE_MARK         0xF\r
329 #define LENGTH_4_DIVIDE         4\r
330 \r
331 PUBLIC void SPI_Init(SPI_INIT_PARM *spi_parm)\r
332 {\r
333         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
334         uint32 temp;\r
335         uint32 ctl0, ctl1, ctl2, ctl3;\r
336 \r
337         /*default clk is 500k 192M /(0xc0 * 2)*/\r
338         spi_ctr_ptr->clkd =0xc0;\r
339 \r
340         temp  = 0;\r
341         temp |= (spi_parm->tx_edge << 1)    |\r
342                 (spi_parm->rx_edge << 0)    |\r
343                 (0x1 << 13) |\r
344                 (spi_parm->msb_lsb_sel<< 7) ;\r
345         spi_ctr_ptr->ctl0 = temp;\r
346 \r
347         spi_ctr_ptr->ctl1 |= BIT_12 | BIT_13;     // set rx/tx mode\r
348 \r
349         /*rx fifo full watermark is 16*/\r
350         spi_ctr_ptr->ctl3 = 0x10;\r
351 \r
352         /*set SPIMODE_3WIRE_9BIT_SDIO mode*/\r
353         spi_ctr_ptr->ctl7 &= ~(0x7 << 3);\r
354         spi_ctr_ptr->ctl7 |= SPIMODE_3WIRE_9BIT_SDIO << 3;\r
355         \r
356         \r
357 \r
358 #if 0\r
359         // set water mark of reveive FIFO\r
360         spi_ctr_ptr->ctl3  = (ctl3 & ~0xFFFF) | \r
361                 ((BURST_SIZE >>2) <<8) | \r
362                 (BURST_SIZE >>2);\r
363 #endif\r
364 }\r
365 \r
366 PUBLIC void SPI_WaitTxFinish()\r
367 {\r
368         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
369 \r
370         while( !(spi_ctr_ptr->iraw)&BIT_8 ) // IS tx finish\r
371         {\r
372         }  \r
373         spi_ctr_ptr->iclr |= BIT_8;\r
374 \r
375         // Wait for spi bus idle\r
376         while((spi_ctr_ptr->sts2)&BIT_8) \r
377         {\r
378         }\r
379         // Wait for tx real empty\r
380         while( !((spi_ctr_ptr->sts2)&BIT_7) ) \r
381         {\r
382         }      \r
383 }\r
384 \r
385 PUBLIC void SPI_WriteData(uint32 data, uint32 data_len, uint32 dummy_bitlen)\r
386 {\r
387         uint32 command;\r
388         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
389 \r
390         // The unit of data_len is identical with buswidth\r
391         SPI_SetTxLen(data_len, dummy_bitlen);\r
392         SPI_TxReq( );\r
393 \r
394         spi_ctr_ptr->data = data;\r
395 \r
396         SPI_WaitTxFinish();\r
397 }\r
398 \r
399 PUBLIC uint32 SPI_ReadData( uint32 data_len, uint32 dummy_bitlen )\r
400 {\r
401         uint32 read_data=0, rxt_cnt=0;\r
402         volatile SPI_CTL_REG_T *spi_ctr_ptr = (volatile SPI_CTL_REG_T *)(SPI_USED_BASE);\r
403 \r
404         // The unit of data_len is identical with buswidth\r
405         SPI_SetRxLen(data_len, dummy_bitlen);\r
406         SPI_RxReq( );\r
407 \r
408         //Wait for spi receive finish\r
409         while( !((spi_ctr_ptr->iraw)&BIT_9) )\r
410         {\r
411                 //wait rxt fifo full\r
412                 if((spi_ctr_ptr->iraw)&BIT_6)\r
413                 {\r
414                         rxt_cnt = (spi_ctr_ptr->ctl3)&0x1F;\r
415                         //SCI_TraceLow("---FIFOFULL:rxt_cnt=0x%x", rxt_cnt);\r
416                         while(rxt_cnt--)\r
417                         {\r
418                                 read_data = spi_ctr_ptr->data;   \r
419                                 //SCI_TraceLow("---FIFOFULL: SPI_ReadData =0x%x", read_data);\r
420                         }\r
421                 }\r
422         }\r
423 \r
424         // Wait for spi bus idle\r
425         while((spi_ctr_ptr->sts2)&BIT_8) \r
426         {\r
427         }\r
428 \r
429         //\r
430         while(data_len--)\r
431         {\r
432                 read_data = spi_ctr_ptr->data;   \r
433                 //SCI_TraceLow("---Finish: SPI_ReadData =0x%x", read_data);\r
434         }\r
435 \r
436         return (read_data);\r
437 }\r