Initial commit
[kernel/linux-3.0.git] / drivers / media / video / samsung / tsi / s3c-tsi.c
1 /* linux/drivers/media/video/samsung/s3c-tsi.c
2  *
3  * Driver file for Samsung Transport Stream Interface
4  *
5  *  Copyright (c) 2009 Samsung Electronics
6  *      http://www.samsungsemi.com/
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 #include <linux/version.h>
13 #include <linux/module.h>
14 #include <linux/fs.h>
15 #include <linux/uaccess.h>
16 #include <linux/interrupt.h>
17 #include <linux/init.h>
18 #include <linux/miscdevice.h>
19 #include <linux/clk.h>
20 #include <linux/platform_device.h>
21 #include <linux/dma-mapping.h>
22 #include <asm/io.h>
23 #include <asm/page.h>
24 #include <mach/irqs.h>
25 #include <mach/gpio.h>
26 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
27 #include <mach/map.h>
28 #include <mach/regs-clock.h>
29 #include <mach/regs-tsi.h>
30 #else
31 #include <plat/map.h>
32 #include <plat/regs-clock.h>
33 #include <plat/regs-tsi.h>
34 #endif
35 #include <plat/gpio-cfg.h>
36
37 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
38 #include <linux/sched.h>
39 #include <linux/wait.h>
40 #include <linux/poll.h>
41 #include <linux/slab.h>
42 #endif
43
44 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
45 #define TSI_BUF_SIZE    (128*1024)
46 #define TSI_PKT_CNT      16
47 #else
48 #define TSI_BUF_SIZE    (256*1024)
49 #endif
50
51 enum filter_mode        {
52         OFF,
53         ON
54 };
55
56 enum pid_filter_mode    {
57         BYPASS = 0,
58         FILTERING
59 };
60
61 enum data_byte_order    {
62         MSB2LSB = 0,
63         LSB2MSB
64 };
65 typedef struct  {
66   struct list_head list;
67   dma_addr_t addr;
68   void *buf;
69   u32 len;
70 } tsi_pkt;
71
72
73 typedef struct  {
74         enum filter_mode flt_mode;
75         enum pid_filter_mode pid_flt_mode;
76         enum data_byte_order byte_order;
77         u16  burst_len;
78         u8  sync_detect;
79         u8  byte_swap;
80         u16 pad_pattern;
81         u16 num_packet;
82 } s3c_tsi_conf;
83
84
85 typedef struct {
86         spinlock_t tsi_lock;
87         struct clk *tsi_clk;
88         struct resource *tsi_mem;
89 /*      struct resource *tsi_irq;       */
90         void __iomem    *tsi_base;
91         int tsi_irq;
92         int running;
93 #if defined(CONFIG_PM) && defined(CONFIG_TARGET_LOCALE_NTT)
94         int last_running_state;
95 #endif
96         int new_pkt;
97         dma_addr_t      tsi_buf_phy;
98         void    *tsi_buf_virt;
99         u32             tsi_buf_size;
100         s3c_tsi_conf *tsi_conf;
101         struct list_head free_list;
102         struct list_head full_list;
103         struct list_head partial_list;
104         wait_queue_head_t read_wq;
105 } tsi_dev;
106
107 tsi_dev *tsi_priv;
108
109 static struct platform_device *s3c_tsi_dev;
110
111 /* #define DRIVER_LOGIC_CHK */
112 #ifdef DRIVER_LOGIC_CHK
113 static struct timer_list tsi_timer;
114 #endif
115
116
117 /* debug macro */
118 #define TSI_DEBUG(fmt, ...)                                     \
119                 do {                                                    \
120                         printk(                                                         \
121                         "%s: " fmt, __func__, ##__VA_ARGS__);                           \
122                 } while (0)
123
124 #define TSI_WARN(fmt, ...)                                      \
125                 do {                                                    \
126                         printk(KERN_WARNING                                     \
127                         fmt, ##__VA_ARGS__);                                            \
128                 } while (0)
129
130 #define TSI_ERROR(fmt, ...)                                     \
131                 do {                                                    \
132                         printk(KERN_ERR                                         \
133                         "%s: " fmt, __func__, ##__VA_ARGS__);                           \
134                 } while (0)
135
136
137 /*#define CONFIG_VIDEO_TSI_DEBUG */
138 #ifdef CONFIG_VIDEO_TSI_DEBUG
139 #define tsi_dbg(fmt, ...)               TSI_DEBUG(fmt, ##__VA_ARGS__)
140 #else
141 #define tsi_dbg(fmt, ...)
142 #endif
143
144 #define tsi_warn(fmt, ...)              TSI_WARN(fmt, ##__VA_ARGS__)
145 #define tsi_err(fmt, ...)               TSI_ERROR(fmt, ##__VA_ARGS__)
146
147 #define tsi_list_dbg(fmt, ...)          TSI_DEBUG(fmt, ##__VA_ARGS__)
148
149
150 #ifdef CONFIG_TSI_LIST_DEBUG
151 void list_debug(struct list_head *head)
152 {
153         int i;
154         tsi_pkt *pkt;
155         /* tsi_list_dbg("DEBUGGING FREE LIST\n"); */
156     i = 1;
157         list_for_each_entry(pkt, head, list)    {
158         tsi_list_dbg(" node %d node_addr %x physical add %p virt add %p size %d\n",
159                                         i, pkt, pkt->addr, pkt->buf, pkt->len);
160                 i++;
161         }
162 }
163 #endif
164
165 /*This should be done in platform*/
166 void s3c_tsi_set_gpio(void)
167 {
168         /*  CLK */
169         s3c_gpio_cfgpin(EXYNOS4210_GPE0(0), S3C_GPIO_SFN(4));
170         s3c_gpio_setpull(EXYNOS4210_GPE0(0), S3C_GPIO_PULL_NONE);
171
172         /*  DTEN */
173         s3c_gpio_cfgpin(EXYNOS4210_GPE0(2), S3C_GPIO_SFN(4));
174         s3c_gpio_setpull(EXYNOS4210_GPE0(2), S3C_GPIO_PULL_NONE);
175
176 #if defined(CONFIG_TARGET_LOCALE_NTT)
177         printk(" %s : system_rev %d\n", __func__, system_rev);
178
179         if (system_rev >= 11) {
180                 /*  DATA */
181                 s3c_gpio_cfgpin(EXYNOS4210_GPE0(3), S3C_GPIO_SFN(4));
182                 s3c_gpio_setpull(EXYNOS4210_GPE0(3), S3C_GPIO_PULL_NONE);
183         }
184 #else
185         /*  DATA */
186         s3c_gpio_cfgpin(S5PV310_GPE0(3), S3C_GPIO_SFN(4));
187         s3c_gpio_setpull(S5PV310_GPE0(3), S3C_GPIO_PULL_NONE);
188 #endif
189
190 #if !defined(CONFIG_TARGET_LOCALE_NTT)
191         /*  SYNC */
192         s3c_gpio_cfgpin(S5PV310_GPE0(1), S3C_GPIO_SFN(4));
193         s3c_gpio_setpull(S5PV310_GPE0(1), S3C_GPIO_PULL_NONE);
194 #endif
195 }
196
197
198 void s3c_tsi_reset(tsi_dev *tsi)
199 {
200         u32 tscon;
201         tscon = readl((tsi->tsi_base + S3C_TS_CON));
202         tscon |= S3C_TSI_SWRESET  ;
203         writel(tscon, (tsi->tsi_base + S3C_TS_CON));
204 }
205
206 void s3c_tsi_set_timeout(u32 count, tsi_dev *tsi)
207 {
208         writel(count, (tsi->tsi_base + S3C_TS_CNT));
209 }
210
211 tsi_pkt *tsi_get_pkt(tsi_dev *tsi, struct list_head *head)
212 {
213         unsigned long flags;
214         tsi_pkt *pkt;
215         spin_lock_irqsave(&tsi->tsi_lock, flags);
216
217         if (list_empty(head))   {
218                 tsi_err("TSI %p list is null\n", head);
219                 spin_unlock_irqrestore(&tsi->tsi_lock, flags);
220                 return NULL;
221         }
222         pkt = list_first_entry(head, tsi_pkt, list);
223         spin_unlock_irqrestore(&tsi->tsi_lock, flags);
224
225         return pkt;
226 }
227
228 void s3c_tsi_set_dest_addr(dma_addr_t addr, u32 reg)
229 {
230          writel(addr, reg);
231 }
232
233 void s3c_tsi_set_sync_mode(u8 mode, u32 reg)
234 {
235         writel(mode, reg);
236 }
237
238 void s3c_tsi_set_clock(u8 enable, u32 reg)
239 {
240         u32 val = 0;
241         if (enable)
242                 val |= 0x1;
243         writel(val, reg);
244 }
245
246 void tsi_enable_interrupts(tsi_dev *tsi)
247 {
248         u32 mask;
249         /* Enable all the interrupts... */
250         mask = 0xFF;
251         writel(mask, (tsi->tsi_base + S3C_TS_INTMASK));
252 }
253
254 void tsi_disable_interrupts(tsi_dev *tsi)
255 {
256         writel(0, (tsi->tsi_base + S3C_TS_INTMASK));
257 }
258
259 static int s3c_tsi_start(tsi_dev *tsi)
260 {
261         unsigned long flags;
262         u32 pkt_size;
263         tsi_pkt *pkt1;
264         pkt1 =  tsi_get_pkt(tsi, &tsi->free_list);
265         if (pkt1 == NULL)       {
266                 tsi_err("Failed to start TSI--No buffers avaialble\n");
267                 return -1;
268         }
269         pkt_size = pkt1->len;
270 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
271         /*      when set the TS BUF SIZE to the S3C_TS_SIZE,
272         if you want get a 10-block TS from TSIF,
273         you should set the value of S3C_TS_SIZE as 47*10(not 188*10)
274         This register get a value of word-multiple values.
275         So, pkt_size which is counted to BYTES must be divided by 4
276         (2 bit shift lefted)
277         Commented by sjinu, 2009_03_18
278         */
279         writel(pkt_size>>2, (tsi->tsi_base+S3C_TS_SIZE));
280 #else
281         writel(pkt_size, (tsi->tsi_base+S3C_TS_SIZE));
282 #endif
283         s3c_tsi_set_dest_addr(pkt1->addr, (u32)(tsi->tsi_base+S3C_TS_BASE));
284
285         spin_lock_irqsave(&tsi->tsi_lock, flags);
286         list_move_tail(&pkt1->list, &tsi->partial_list);
287         spin_unlock_irqrestore(&tsi->tsi_lock, flags);
288         /* start the clock */
289         s3c_tsi_set_clock(TSI_CLK_START, (u32)(tsi->tsi_base+S3C_TS_CLKCON));
290         /* set the next buffer immediatly */
291         pkt1 =  tsi_get_pkt(tsi, &tsi->free_list);
292         if (pkt1 == NULL)       {
293                 tsi_err("Failed to start TSI--No buffers avaialble\n");
294                 return -1;
295         }
296         s3c_tsi_set_dest_addr(pkt1->addr, (u32)(tsi->tsi_base+S3C_TS_BASE));
297         spin_lock_irqsave(&tsi->tsi_lock, flags);
298         list_move_tail(&pkt1->list, &tsi->partial_list);
299         spin_unlock_irqrestore(&tsi->tsi_lock, flags);
300         tsi_enable_interrupts(tsi);
301
302 #ifdef CONFIG_TSI_LIST_DEBUG1
303         tsi_list_dbg("Debugging Partial list\n");
304         list_debug(&tsi->partial_list);
305         tsi_list_dbg("Debugging free list\n");
306         list_debug(&tsi->free_list);
307 #endif
308         return 0;
309 }
310
311 static int s3c_tsi_stop(tsi_dev *tsi)
312 {
313         unsigned long flags;
314         tsi_pkt *pkt;
315         struct list_head *full = &tsi->full_list;
316         struct list_head *partial = &tsi->partial_list;
317
318         spin_lock_irqsave(&tsi->tsi_lock, flags);
319         #ifdef DRIVER_LOGIC_CHK
320         del_timer(&tsi_timer);
321         #endif
322
323         tsi_disable_interrupts(tsi);
324         s3c_tsi_set_clock(TSI_CLK_STOP, (u32)(tsi->tsi_base+S3C_TS_CLKCON));
325         /* move all the packets from partial and full list to free list */
326         while (!list_empty(full))       {
327                 pkt = list_entry(full->next, tsi_pkt, list);
328                 list_move_tail(&pkt->list, &tsi->free_list);
329         }
330
331         while (!list_empty(partial))    {
332                 pkt = list_entry(partial->next, tsi_pkt, list);
333                 list_move_tail(&pkt->list, &tsi->free_list);
334         }
335         tsi->running = 0;
336         tsi_priv->new_pkt = 0;
337         spin_unlock_irqrestore(&tsi->tsi_lock, flags);
338
339         return 0;
340 }
341
342 void s3c_tsi_setup(tsi_dev *tsi)
343 {
344         u32 tscon;
345         s3c_tsi_conf *conf = tsi->tsi_conf;
346         s3c_tsi_reset(tsi);
347         s3c_tsi_set_timeout(TS_TIMEOUT_CNT_MAX, tsi);
348
349         tscon = readl((tsi->tsi_base+S3C_TS_CON));
350
351         tscon &= ~(S3C_TSI_SWRESET_MASK|S3C_TSI_CLKFILTER_MASK|
352                 S3C_TSI_BURST_LEN_MASK | S3C_TSI_INT_FIFO_FULL_INT_ENA_MASK |
353                 S3C_TSI_SYNC_MISMATCH_INT_MASK | S3C_TSI_PSUF_INT_MASK|
354                 S3C_TSI_PSOF_INT_MASK | S3C_TSI_TS_CLK_TIME_OUT_INT_MASK |
355                 S3C_TSI_TS_ERROR_MASK | S3C_TSI_PID_FILTER_MASK |
356                 S3C_TSI_ERROR_ACTIVE_MASK | S3C_TSI_DATA_BYTE_ORDER_MASK |
357                 S3C_TSI_TS_VALID_ACTIVE_MASK | S3C_TSI_SYNC_ACTIVE_MASK |
358                 S3C_TSI_CLK_INVERT_MASK);
359
360         tscon |= (conf->flt_mode << S3C_TSI_CLKFILTER_SHIFT);
361         tscon |= (conf->pid_flt_mode << S3C_TSI_PID_FILTER_SHIFT);
362         tscon |= (conf->byte_order << S3C_TSI_DATA_BYTE_ORDER_SHIFT);
363         tscon |= (conf->burst_len << S3C_TSI_BURST_LEN_SHIFT);
364         tscon |= (conf->pad_pattern << S3C_TSI_PAD_PATTERN_SHIFT);
365
366         tscon |= (S3C_TSI_OUT_BUF_FULL_INT_ENA | S3C_TSI_INT_FIFO_FULL_INT_ENA);
367         tscon |= (S3C_TSI_SYNC_MISMATCH_INT_SKIP | S3C_TSI_PSUF_INT_SKIP |
368                                         S3C_TSI_PSOF_INT_SKIP);
369         tscon |= (S3C_TSI_TS_CLK_TIME_OUT_INT);
370         /* These values are bd dependent? */
371         tscon |= (S3C_TSI_TS_VALID_ACTIVE_HIGH | S3C_TSI_CLK_INVERT_HIGH);
372         writel(tscon, (tsi->tsi_base+S3C_TS_CON));
373         s3c_tsi_set_sync_mode(conf->sync_detect, (u32)(tsi->tsi_base+S3C_TS_SYNC));
374 }
375
376 void s3c_tsi_rx_int(tsi_dev *tsi)
377 {
378         tsi_pkt *pkt;
379         /* deque the pcket from partial list to full list
380                 incase the free list is empty, stop the tsi.. */
381
382         pkt = tsi_get_pkt(tsi, &tsi->partial_list);
383
384         /* this situation should not come.. stop_tsi */
385         if (pkt == NULL)        {
386                 tsi_err("TSI..Receive interrupt without buffer\n");
387                 s3c_tsi_stop(tsi);
388                 return;
389         }
390
391         tsi_dbg("moving %p node %x phy %p virt to full list\n",
392                         pkt, pkt->addr, pkt->buf);
393
394         list_move_tail(&pkt->list, &tsi->full_list);
395
396         pkt = tsi_get_pkt(tsi, &tsi->free_list);
397         if (pkt == NULL)        {
398                 /* this situation should not come.. stop_tsi */
399                 tsi_err("TSI..No more free bufs..stopping channel\n");
400                 s3c_tsi_stop(tsi);
401                 return;
402         }
403         list_move_tail(&pkt->list, &tsi->partial_list);
404
405 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
406         /*      namkh, request from Abraham
407                 If there arise a buffer-full interrupt,
408                 a new ts buffer address should be set.
409
410                 Commented by sjinu, 2009_03_18  */
411         s3c_tsi_set_dest_addr(pkt->addr, (u32)(tsi->tsi_base+S3C_TS_BASE));
412 #endif
413
414 #ifdef CONFIG_TSI_LIST_DEBUG
415         tsi_list_dbg("Debugging Full list\n");
416         list_debug(&tsi->full_list);
417         tsi_list_dbg("Debugging Partial list\n");
418         list_debug(&tsi->partial_list);
419 #endif
420         tsi->new_pkt = 1;
421         wake_up(&tsi->read_wq);
422 }
423
424
425 static irqreturn_t s3c_tsi_irq(int irq, void *dev_id)
426 {
427         u32 intpnd;
428         tsi_dev *tsi = platform_get_drvdata((struct platform_device *)dev_id);
429         intpnd = readl(tsi->tsi_base + S3C_TS_INT);
430         tsi_dbg("INTPND is %x\n", intpnd);
431         writel(intpnd, (tsi->tsi_base+S3C_TS_INT));
432
433         if (intpnd & S3C_TSI_OUT_BUF_FULL)
434                 s3c_tsi_rx_int(tsi);
435         return IRQ_HANDLED;
436 }
437
438 static int s3c_tsi_release(struct inode *inode, struct file *file)
439 {
440         int ret = 0;
441         tsi_dev *tsi = file->private_data;
442         tsi_dbg("TSI_RELEASE\n");
443         if (tsi->running)       {
444                 tsi_dbg("TSI_RELEASE stopping\n");
445                 tsi->running = 0;
446                 ret = s3c_tsi_stop(tsi);
447                 tsi_dbg("TSI_RELEASE LIST cleaned\n");
448         }
449
450 #ifdef CONFIG_TSI_LIST_DEBUG
451         tsi_list_dbg("Debugging Full list\n");
452         list_debug(&tsi->full_list);
453         tsi_list_dbg("Debugging Partial list\n");
454         list_debug(&tsi->partial_list);
455 #endif
456
457         return ret;
458 }
459
460 int s3c_tsi_mmap(struct file *filp, struct vm_area_struct *vma)
461 {
462         return 0;
463 }
464
465 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
466 static unsigned int     s3c_tsi_poll(struct file *file, poll_table *wait)
467 {
468         unsigned int mask = 0;
469         tsi_dev *tsi = file->private_data;
470
471         poll_wait(file, &tsi->read_wq, wait);
472
473         if (tsi->new_pkt)
474                 mask |= (POLLIN | POLLRDNORM);
475
476         return mask;
477 }
478 #endif
479
480 static ssize_t s3c_tsi_read(struct file *file, char *buf, size_t count, loff_t *pos)
481 {
482         unsigned long flags;
483         int ret = 0;
484         u32 len = 0, pkt_size = 0;
485         tsi_pkt *pkt;
486         tsi_dev *tsi = file->private_data;
487         struct list_head *full = &tsi->full_list;
488
489 #ifdef CONFIG_TSI_LIST_DEBUG
490         tsi_list_dbg("Debugging Full list\n");
491         tsi_dbg("count is %d\n", count);
492         list_debug(&tsi->full_list);
493 #endif
494
495 #if defined(CONFIG_CPU_S5PV210)  || defined(CONFIG_TARGET_LOCALE_NTT)
496         ret = wait_event_interruptible(tsi->read_wq, tsi->new_pkt);
497         if (ret < 0)    {
498                 tsi_dbg("woken up from signal..returning\n");
499                 return ret;
500         }
501         pkt = tsi_get_pkt(tsi, full);
502
503         pkt_size = pkt->len;    /* pkt_size should be multiple of 188 bytes. */
504
505         tsi_dbg("pkt_size is %d\n", pkt_size);
506                 if (pkt_size > count)
507                         pkt_size = count;
508
509                 if (copy_to_user((buf+len), pkt->buf, pkt_size)) {
510                         tsi_dbg("copy user fail\n");
511                         ret = -EFAULT;
512                         return ret;
513                 }
514
515                 len += pkt_size;
516                 count -= pkt_size;
517                 tsi_dbg("len is%d count %d pkt_size %d\n", len, count, pkt_size);
518                 ret = len;
519                 spin_lock_irqsave(&tsi->tsi_lock, flags);
520                 list_move(&pkt->list, &tsi->free_list);
521                 spin_unlock_irqrestore(&tsi->tsi_lock, flags);
522
523                 if (list_empty(full))
524                         tsi->new_pkt = 0;
525 #else
526         while (count > 0)       {
527                 /* deque packet from full list */
528                 pkt = tsi_get_pkt(tsi, full);
529                 if (pkt == NULL)        {
530                         ret = wait_event_interruptible(tsi->read_wq, tsi->new_pkt);
531
532                         if (ret < 0)            {
533                                 tsi_dbg("woken up from signal..returning\n");
534                                 return ret;
535                         }
536                         tsi_dbg("woken up proprt\n");
537                         pkt = tsi_get_pkt(tsi, full);
538
539                 }
540                 pkt_size = pkt->len * 4;
541                 if (pkt_size > count)
542                         pkt_size = count;
543
544                 if (copy_to_user((buf+len), pkt->buf, pkt_size))        {
545                         tsi_dbg("copy user fail\n");
546                         ret = -EFAULT;
547                         break;
548                 }
549
550                 len += pkt_size;
551                 count -= pkt_size;
552                 tsi_dbg("len is%d count %d pkt_size %d\n", len, count, pkt_size);
553                 ret = len;
554                 spin_lock_irqsave(&tsi->tsi_lock, flags);
555                 list_move(&pkt->list, &tsi->free_list);
556                 spin_unlock_irqrestore(&tsi->tsi_lock, flags);
557
558                 if (list_empty(full))
559                         tsi->new_pkt = 0;
560         }
561 #endif
562
563 #ifdef CONFIG_TSI_LIST_DEBUG1
564         tsi_list_dbg("Debugging Free list\n");
565         list_debug(&tsi->free_list);
566 #endif
567         return ret;
568 }
569
570 #define TSI_TRIGGER     0xAABB
571 #define TSI_STOP        0xAACC
572
573 static long s3c_tsi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
574 {
575         int ret = 0;
576         tsi_dev *tsi = platform_get_drvdata(s3c_tsi_dev);
577         /* currently only two ioctl for tigger and stop are provided.. */
578         tsi_dbg("TSI cmd is %x\n", cmd);
579         switch (cmd)    {
580                 case TSI_TRIGGER:
581                         if (tsi->running)
582                                 return -EBUSY;
583                         tsi->running = 1;
584                         ret = s3c_tsi_start(tsi);
585                 #ifdef DRIVER_LOGIC_CHK
586                         tsi_timer.expires = jiffies + HZ/10;
587                         add_timer(&tsi_timer);
588                 #endif
589                         break;
590                 case TSI_STOP:
591                         tsi->running = 0;
592                         ret =   s3c_tsi_stop(tsi);
593                         break;
594                 default:
595                         break;
596         }
597         return ret;
598 }
599
600 static int s3c_tsi_open(struct inode *inode, struct file *file)
601 {
602         tsi_dev *s3c_tsi = platform_get_drvdata(s3c_tsi_dev);
603         tsi_dbg(" %s\n", __func__);
604 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
605         /* Fix the TSI data problem (Don't generated waking up sleep state)
606         clk_enable(s3c_tsi->tsi_clk);
607         */
608         s3c_tsi_setup(s3c_tsi);
609 #endif
610         file->private_data = s3c_tsi;
611         return 0;
612 }
613
614 static struct file_operations tsi_fops = {
615         owner:          THIS_MODULE,
616         open :          s3c_tsi_open,
617         release :       s3c_tsi_release,
618         unlocked_ioctl          :       s3c_tsi_ioctl,
619         read :          s3c_tsi_read,
620 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
621         poll :          s3c_tsi_poll,
622 #endif
623         mmap :          s3c_tsi_mmap,
624 };
625
626
627 static struct miscdevice s3c_tsi_miscdev = {
628         minor:          MISC_DYNAMIC_MINOR,
629         name :          "s3c-tsi",
630         fops :          &tsi_fops
631 };
632
633 static int tsi_setup_bufs(tsi_dev *dev, struct list_head *head)
634 {
635         tsi_pkt *pkt;
636         u32 tsi_virt, tsi_size, buf_size;
637         u16 num_buf;
638         dma_addr_t tsi_phy;
639         int i;
640
641         tsi_phy = dev->tsi_buf_phy;
642         tsi_virt = (u32) dev->tsi_buf_virt;
643         tsi_size = dev->tsi_buf_size;
644 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
645         /* TSI generates interrupt after filling this many bytes */
646         buf_size = dev->tsi_conf->num_packet * TS_PKT_SIZE*TSI_PKT_CNT;
647 #else
648         /* TSI generates interrupt after filling this many bytes */
649         buf_size = dev->tsi_conf->num_packet * TS_PKT_SIZE;
650 #endif
651         num_buf = (tsi_size / buf_size);
652
653         for (i = 0; i < num_buf; i++)   {
654                 pkt = kmalloc(sizeof(tsi_pkt), GFP_KERNEL);
655                 if (!pkt)
656                         return list_empty(head) ? -ENOMEM : 0 ;
657 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
658                 /*      Address should be byte-aligned
659                         Commented by sjinu, 2009_03_18  */
660                 pkt->addr = ((u32)tsi_phy + i*buf_size);
661                 pkt->buf = (void *)(u8 *)((u32)tsi_virt + i*buf_size);
662 #else
663                 pkt->addr = (tsi_phy + i*4*buf_size);
664                 pkt->buf = (void *)(tsi_virt + i*4*buf_size);
665 #endif
666                 pkt->len = buf_size;
667                 list_add_tail(&pkt->list, head);
668         }
669
670         tsi_dbg("total nodes calulated %d buf_size %d\n", num_buf, buf_size);
671 #ifdef CONFIG_TSI_LIST_DEBUG1
672         list_debug(head);
673 #endif
674
675 return 0;
676
677 }
678
679 #ifdef DRIVER_LOGIC_CHK
680 int timer_count = 100;
681
682 void tsi_timer_function(u32 dev)
683 {
684         tsi_dev *tsi = (tsi_dev *)(dev);
685         s3c_tsi_rx_int(tsi);
686         tsi_timer.expires = jiffies + HZ/100;
687         timer_count--;
688         if (timer_count > 0)
689                 add_timer(&tsi_timer);
690 }
691 #endif
692
693 static int s3c_tsi_probe(struct platform_device *pdev)
694 {
695         struct resource *res;
696         static int              size;
697         static int              ret;
698         s3c_tsi_conf    *conf;
699         dma_addr_t              map_dma;
700         struct device *dev = &pdev->dev;
701
702         tsi_dbg(" %s\n", __func__);
703         tsi_priv = kmalloc(sizeof(tsi_dev), GFP_KERNEL);
704         if (tsi_priv == NULL)   {
705                 printk("NO Memory for tsi allocation\n");
706                 return -ENOMEM;
707         }
708         conf = kmalloc(sizeof(s3c_tsi_conf), GFP_KERNEL);
709         if (conf == NULL)       {
710                 printk("NO Memory for tsi conf allocation\n");
711                 kfree(tsi_priv);
712                 return -ENOMEM;
713         }
714         /* Initialise the dafault conf parameters..
715          * this should be obtained from the platform data and ioctl
716          * move this to platform later */
717
718         conf->flt_mode    = OFF;
719         conf->pid_flt_mode = BYPASS;
720         conf->byte_order = MSB2LSB;
721 #if defined(CONFIG_TARGET_LOCALE_NTT)
722         conf->sync_detect = S3C_TSI_SYNC_DET_MODE_TS_SYNC_BYTE;
723 #else
724         conf->sync_detect = S3C_TSI_SYNC_DET_MODE_TS_SYNC8;
725 #endif
726
727 #if defined(CONFIG_CPU_S5PV210) || defined(CONFIG_TARGET_LOCALE_NTT)
728         /*
729          to avoid making interrupt during getting the TS from TS buffer,
730          we use the burst-length as 8 beat.
731          This burst-length may be changed next time.
732          Commented by sjinu, 2009_03_18
733         */
734         conf->burst_len = 2;
735 #else
736         conf->burst_len = 0;
737 #endif
738         conf->byte_swap = 1;    /* little endian */
739         conf->pad_pattern = 0;  /* this might vary from bd to bd */
740         conf->num_packet = TS_NUM_PKT;  /* this might vary from bd to bd */
741
742         tsi_priv->tsi_conf = conf;
743         tsi_priv->tsi_buf_size = TSI_BUF_SIZE;
744
745         tsi_priv->tsi_clk = clk_get(NULL, "tsi");
746         //printk("Clk Get Result %x\n", tsi_priv->tsi_clk);
747         if (tsi_priv->tsi_clk == NULL)  {
748                         printk(KERN_ERR "Failed to get TSI clock\n");
749                         return -ENOENT;
750         }
751         clk_enable(tsi_priv->tsi_clk);
752
753         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
754
755         if (res == NULL)        {
756                 tsi_err("failed to get memory region resouce\n");
757                 return -ENOENT;
758         }
759
760         size = (res->end - res->start) + 1;
761         tsi_priv->tsi_mem = request_mem_region(res->start, size, pdev->name);
762
763         if (tsi_priv->tsi_mem  == NULL) {
764                 tsi_err("failed to get memory region\n");
765                 return -ENOENT;
766         }
767
768         ret = platform_get_irq(pdev, 0);
769
770         if (ret == 0)   {
771                 tsi_err("failed to get irq resource\n");
772                 ret = -ENOENT;
773                 goto err_res;
774         }
775
776         tsi_priv->tsi_irq = ret;
777         ret = request_irq(tsi_priv->tsi_irq, (void *)s3c_tsi_irq, 0, pdev->name, pdev);
778
779         if (ret != 0)   {
780                 tsi_err("failed to install irq (%d)\n", ret);
781                 goto err_res;
782         }
783
784         tsi_priv->tsi_base = ioremap(tsi_priv->tsi_mem->start, size);
785
786         if (tsi_priv->tsi_base == 0)    {
787                 tsi_err("failed to ioremap() region\n");
788                 ret = -EINVAL;
789                 goto err_irq;
790         }
791
792         INIT_LIST_HEAD(&tsi_priv->free_list);
793         INIT_LIST_HEAD(&tsi_priv->full_list);
794         INIT_LIST_HEAD(&tsi_priv->partial_list);
795         spin_lock_init(&tsi_priv->tsi_lock);
796         init_waitqueue_head(&tsi_priv->read_wq);
797         tsi_priv->new_pkt = 0;
798         tsi_priv->running = 0;
799 #if defined(CONFIG_PM) && defined(CONFIG_TARGET_LOCALE_NTT)
800         tsi_priv->last_running_state = tsi_priv->running;
801 #endif
802
803         /* get the dma coherent mem */
804         tsi_priv->tsi_buf_virt = dma_alloc_coherent(dev, tsi_priv->tsi_buf_size, &map_dma, GFP_KERNEL);
805         if (tsi_priv->tsi_buf_virt == NULL)     {
806                 tsi_err("Failed to claim TSI memory\n");
807                 ret = -ENOMEM;
808                 goto err_map;
809         }
810
811         tsi_dbg("TSI dev dma mem phy %x virt %p\n", map_dma, tsi_priv->tsi_buf_virt);
812
813         tsi_priv->tsi_buf_phy = map_dma;
814
815         ret = tsi_setup_bufs(tsi_priv, &tsi_priv->free_list);
816         if (ret)        {
817                 tsi_err("TSI failed to setup pkt list");
818                 goto err_clk;
819         }
820
821         platform_set_drvdata(pdev, tsi_priv);
822         s3c_tsi_set_gpio();
823         s3c_tsi_setup(tsi_priv);
824         s3c_tsi_dev = pdev;
825         ret = misc_register(&s3c_tsi_miscdev);
826         if (ret)        {
827                 tsi_err("Unable to register the s3c-tsi driver\n");
828                 goto err_clk;
829         }
830
831 #ifdef DRIVER_LOGIC_CHK
832         init_timer(&tsi_timer);
833         tsi_timer.function = tsi_timer_function;
834         tsi_timer.data = (unsigned long) tsi_priv;
835 /*
836         s3c_tsi_start(tsi_priv);
837         s3c_tsi_rx_int(tsi_priv);
838 */
839 #endif
840
841         return 0;
842
843 err_clk:
844           clk_disable(tsi_priv->tsi_clk);
845 err_map:
846         iounmap(tsi_priv->tsi_base);
847 err_irq:
848         free_irq(tsi_priv->tsi_irq, pdev);
849 err_res:
850         release_resource(tsi_priv->tsi_mem);
851         kfree(tsi_priv);
852
853         return ret;
854 }
855
856 static void tsi_free_packets(tsi_dev *tsi)
857 {
858         tsi_pkt *pkt;
859         struct list_head *head = &(tsi->free_list);
860
861         while (!list_empty(head))       {
862                 pkt = list_entry(head->next, tsi_pkt, list);
863                 list_del(&pkt->list);
864                 kfree(pkt);
865         }
866 }
867
868 static int s3c_tsi_remove(struct platform_device *dev)
869 {
870         tsi_dev *tsi = platform_get_drvdata((struct platform_device *)dev);
871         if (tsi->running)
872                 s3c_tsi_stop(tsi);
873
874         /* free allocated memory and nodes */
875         tsi_free_packets(tsi);
876         free_irq(tsi->tsi_irq, dev);
877         dma_free_coherent(&dev->dev, tsi->tsi_buf_size, tsi->tsi_buf_virt, tsi->tsi_buf_phy);
878         kfree(tsi);
879         return 0;
880 }
881
882
883 #if defined(CONFIG_PM) && defined(CONFIG_TARGET_LOCALE_NTT)
884 static int s3c_tsi_suspend(struct platform_device *pdev, pm_message_t state)
885 {
886         tsi_dev *tsi = platform_get_drvdata(s3c_tsi_dev);
887
888         tsi->last_running_state = tsi->running;
889         if (tsi_priv->last_running_state)
890                 s3c_tsi_stop(tsi_priv);
891
892         clk_disable(tsi_priv->tsi_clk);
893
894         return 0;
895 }
896
897 static int s3c_tsi_resume(struct platform_device *pdev)
898 {
899         tsi_dev *tsi = platform_get_drvdata(s3c_tsi_dev);
900
901         clk_enable(tsi_priv->tsi_clk);
902         s3c_tsi_set_gpio();
903         s3c_tsi_setup(tsi_priv);
904
905         if (tsi->last_running_state) {
906                 tsi->running = 1;
907                 s3c_tsi_start(tsi);
908                 s3c_tsi_rx_int(tsi);
909         }
910         return 0;
911 }
912
913 #endif
914
915 static struct platform_driver s3c_tsi_driver = {
916         .probe          = s3c_tsi_probe,
917         .remove         = s3c_tsi_remove,
918         .shutdown       = NULL,
919 #if defined(CONFIG_PM) && defined(CONFIG_TARGET_LOCALE_NTT)
920         .suspend        = s3c_tsi_suspend,
921         .resume         = s3c_tsi_resume,
922 #else
923         .suspend        = NULL,
924         .resume         = NULL,
925 #endif
926         .driver         = {
927                         .owner  = THIS_MODULE,
928                         .name   = "s3c-tsi",
929         },
930 };
931
932
933
934 const char banner[] __initdata =  "TSI Driver Version 1.0\n";
935
936 static int __init s3c_tsi_init(void)
937 {
938         printk(banner);
939         tsi_dbg(" %s\n", __func__);
940         return platform_driver_register(&s3c_tsi_driver);
941 }
942
943
944
945
946 static void __exit s3c_tsi_exit(void)
947 {
948
949         platform_driver_unregister(&s3c_tsi_driver);
950 }
951
952
953
954 module_init(s3c_tsi_init);
955 module_exit(s3c_tsi_exit);
956
957 MODULE_AUTHOR("Samsung");
958 MODULE_DESCRIPTION("S3C TSI Device Driver");
959 MODULE_LICENSE("GPL");