diff options
Diffstat (limited to 'drivers/media/isdbt/fc8150/fc8150.c')
-rw-r--r-- | drivers/media/isdbt/fc8150/fc8150.c | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/drivers/media/isdbt/fc8150/fc8150.c b/drivers/media/isdbt/fc8150/fc8150.c new file mode 100644 index 0000000..f6b829f --- /dev/null +++ b/drivers/media/isdbt/fc8150/fc8150.c @@ -0,0 +1,525 @@ +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <linux/kthread.h> +#include <linux/poll.h> +#include <linux/vmalloc.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio.h> + +#include <linux/io.h> + +#include <mach/gpio.h> + +#include "fc8150.h" +#include "bbm.h" +#include "fci_oal.h" +#include "fci_tun.h" +#include "fc8150_regs.h" +#include "fc8150_isr.h" +#include "fci_hal.h" + +struct ISDBT_INIT_INFO_T *hInit; + +#define RING_BUFFER_SIZE (128 * 1024) /* kmalloc max 128k */ + +/* GPIO(RESET & INTRRUPT) Setting */ +#define FC8150_NAME "isdbt" + +/* +#define GPIO_ISDBT_IRQ 0x24 +#define GPIO_ISDBT_PWR_EN 1 +#define GPIO_ISDBT_RST 2 +*/ +#define GPIO_ISDBT_IRQ_FC8150 EXYNOS4_GPC0(4) +#define GPIO_ISDBT_PWR_EN_FC8150 EXYNOS4_GPC0(2) +#define GPIO_ISDBT_RST_FC8150 EXYNOS4_GPC0(0) + +static DECLARE_WAIT_QUEUE_HEAD(isdbt_isr_wait); + +static u8 isdbt_isr_sig; +static struct task_struct *isdbt_kthread; + +static irqreturn_t isdbt_irq(int irq, void *dev_id) +{ + isdbt_isr_sig = 1; + wake_up_interruptible(&isdbt_isr_wait); + + return IRQ_HANDLED; +} + +int isdbt_hw_setting(void) +{ + int err; + PRINTF(0, "isdbt_hw_setting\n"); + + err = gpio_request(GPIO_ISDBT_PWR_EN_FC8150, "isdbt_en"); + if (err) { + PRINTF(0, "isdbt_hw_setting: Couldn't request isdbt_en\n"); + goto gpio_isdbt_en; + } + gpio_direction_output(GPIO_ISDBT_PWR_EN_FC8150, 0); + + err = gpio_request(GPIO_ISDBT_RST_FC8150, "isdbt_rst"); + if (err) { + PRINTF(0, "isdbt_hw_setting: Couldn't request isdbt_rst\n"); + goto gpio_isdbt_rst; + } + gpio_direction_output(GPIO_ISDBT_RST_FC8150, 1); + + err = gpio_request(GPIO_ISDBT_IRQ_FC8150, "isdbt_irq"); + if (err) { + PRINTF(0, "isdbt_hw_setting: Couldn't request isdbt_irq\n"); + goto gpio_isdbt_rst; + } + gpio_direction_input(GPIO_ISDBT_IRQ_FC8150); + + err = request_irq(gpio_to_irq(GPIO_ISDBT_IRQ_FC8150), isdbt_irq + , IRQF_DISABLED | IRQF_TRIGGER_RISING, FC8150_NAME, NULL); + + if (err < 0) { + PRINTF(0, "isdbt_hw_setting: couldn't request gpio"); + PRINTF(0, "interrupt %d reason(%d)\n" + , gpio_to_irq(GPIO_ISDBT_IRQ_FC8150), err); + goto request_isdbt_irq; + } + return 0; +request_isdbt_irq: + gpio_free(GPIO_ISDBT_IRQ_FC8150); +gpio_isdbt_rst: + gpio_free(GPIO_ISDBT_PWR_EN_FC8150); +gpio_isdbt_en: + return err; +} + +/*POWER_ON & HW_RESET & INTERRUPT_CLEAR */ +void isdbt_hw_init(void) +{ + PRINTF(0, "isdbt_hw_init\n"); + gpio_set_value(GPIO_ISDBT_PWR_EN_FC8150, 1); + gpio_set_value(GPIO_ISDBT_RST_FC8150, 1); + mdelay(5); + gpio_set_value(GPIO_ISDBT_RST_FC8150, 0); + mdelay(1); + gpio_set_value(GPIO_ISDBT_RST_FC8150, 1); +} + +/*POWER_OFF */ +void isdbt_hw_deinit(void) +{ + PRINTF(0, "isdbt_hw_deinit\n"); + gpio_set_value(GPIO_ISDBT_PWR_EN_FC8150, 0); +} + +int data_callback(u32 hDevice, u8 *data, int len) +{ + struct ISDBT_INIT_INFO_T *hInit; + struct list_head *temp; + hInit = (struct ISDBT_INIT_INFO_T *)hDevice; + + list_for_each(temp, &(hInit->hHead)) + { + struct ISDBT_OPEN_INFO_T *hOpen; + + hOpen = list_entry(temp, struct ISDBT_OPEN_INFO_T, hList); + + if (hOpen->isdbttype == TS_TYPE) { + if (fci_ringbuffer_free(&hOpen->RingBuffer) < (len+2)) { + /*PRINTF(hDevice, "f"); */ + return 0; + } + + FCI_RINGBUFFER_WRITE_BYTE(&hOpen->RingBuffer, len >> 8); + FCI_RINGBUFFER_WRITE_BYTE(&hOpen->RingBuffer, + len & 0xff); + + fci_ringbuffer_write(&hOpen->RingBuffer, data, len); + + wake_up_interruptible(&(hOpen->RingBuffer.queue)); + } + } + + return 0; +} + +static int isdbt_thread(void *hDevice) +{ + static DEFINE_MUTEX(thread_lock); + + struct ISDBT_INIT_INFO_T *hInit = (struct ISDBT_INIT_INFO_T *)hDevice; + + set_user_nice(current, -20); + + PRINTF(hInit, "isdbt_kthread enter\n"); + + BBM_TS_CALLBACK_REGISTER((u32)hInit, data_callback); + + while (1) { + wait_event_interruptible(isdbt_isr_wait, + isdbt_isr_sig || kthread_should_stop()); + + isdbt_isr_sig = 0; + + BBM_ISR(hInit); + + if (kthread_should_stop()) + break; + } + + BBM_TS_CALLBACK_DEREGISTER(); + + PRINTF(hInit, "isdbt_kthread exit\n"); + + return 0; +} + +const struct file_operations isdbt_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = isdbt_ioctl, + .open = isdbt_open, + .read = isdbt_read, + .release = isdbt_release, +}; + +static struct miscdevice fc8150_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = FC8150_NAME, + .fops = &isdbt_fops, +}; + +int isdbt_open(struct inode *inode, struct file *filp) +{ + struct ISDBT_OPEN_INFO_T *hOpen; + + PRINTF(hInit, "isdbt open\n"); + + hOpen = kmalloc(sizeof(struct ISDBT_OPEN_INFO_T), GFP_KERNEL); + + hOpen->buf = kmalloc(RING_BUFFER_SIZE, GFP_KERNEL); + hOpen->isdbttype = 0; + + list_add(&(hOpen->hList), &(hInit->hHead)); + + hOpen->hInit = (HANDLE *)hInit; + + if (hOpen->buf == NULL) { + PRINTF(hInit, "ring buffer malloc error\n"); + return -ENOMEM; + } + + fci_ringbuffer_init(&hOpen->RingBuffer, hOpen->buf, RING_BUFFER_SIZE); + + filp->private_data = hOpen; + + return 0; +} + +ssize_t isdbt_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + s32 avail; + s32 non_blocking = filp->f_flags & O_NONBLOCK; + struct ISDBT_OPEN_INFO_T *hOpen + = (struct ISDBT_OPEN_INFO_T *)filp->private_data; + struct fci_ringbuffer *cibuf = &hOpen->RingBuffer; + ssize_t len; + + if (!cibuf->data || !count) { + /*PRINTF(hInit, " return 0\n"); */ + return 0; + } + + if (non_blocking && (fci_ringbuffer_empty(cibuf))) { + /*PRINTF(hInit, "return EWOULDBLOCK\n"); */ + return -EWOULDBLOCK; + } + + if (wait_event_interruptible(cibuf->queue, + !fci_ringbuffer_empty(cibuf))) { + PRINTF(hInit, "return ERESTARTSYS\n"); + return -ERESTARTSYS; + } + + avail = fci_ringbuffer_avail(cibuf); + + if (avail < 4) { + PRINTF(hInit, "return 00\n"); + return 0; + } + + len = FCI_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= FCI_RINGBUFFER_PEEK(cibuf, 1); + + if (avail < len + 2 || count < len) { + PRINTF(hInit, "return EINVAL\n"); + return -EINVAL; + } + + FCI_RINGBUFFER_SKIP(cibuf, 2); + + return fci_ringbuffer_read_user(cibuf, buf, len); +} + +int isdbt_release(struct inode *inode, struct file *filp) +{ + struct ISDBT_OPEN_INFO_T *hOpen; + + PRINTF(hInit, "isdbt_release\n"); + + hOpen = filp->private_data; + + hOpen->isdbttype = 0; + + list_del(&(hOpen->hList)); + kfree(hOpen->buf); + kfree(hOpen); + + return 0; +} + +int fc8150_if_test(void) +{ + int res = 0; + int i; + u16 wdata = 0; + u32 ldata = 0; + u8 data = 0; + u8 temp = 0; + + PRINTF(0, "fc8150_if_test Start!!!\n"); + for (i = 0 ; i < 100 ; i++) { + BBM_BYTE_WRITE(0, 0xa4, i & 0xff); + BBM_BYTE_READ(0, 0xa4, &data); + if ((i & 0xff) != data) { + PRINTF(0, "fc8150_if_btest! i=0x%x, data=0x%x\n" + , i & 0xff, data); + res = 1; + } + } + + for (i = 0 ; i < 100 ; i++) { + BBM_WORD_WRITE(0, 0xa4, i & 0xffff); + BBM_WORD_READ(0, 0xa4, &wdata); + if ((i & 0xffff) != wdata) { + PRINTF(0, "fc8150_if_wtest! i=0x%x, data=0x%x\n" + , i & 0xffff, wdata); + res = 1; + } + } + + for (i = 0 ; i < 100 ; i++) { + BBM_LONG_WRITE(0, 0xa4, i & 0xffffffff); + BBM_LONG_READ(0, 0xa4, &ldata); + if ((i & 0xffffffff) != ldata) { + PRINTF(0, "fc8150_if_ltest! i=0x%x, data=0x%x\n" + , i & 0xffffffff, ldata); + res = 1; + } + } + + for (i = 0 ; i < 100 ; i++) { + temp = i & 0xff; + BBM_TUNER_WRITE(NULL, 0x52, 0x01, &temp, 0x01); + BBM_TUNER_READ(NULL, 0x52, 0x01, &data, 0x01); + if ((i & 0xff) != data) + PRINTF(0, "FC8150 tuner test (0x%x,0x%x)\n" + , i & 0xff, data); + } + + PRINTF(0, "fc8150_if_test End!!!\n"); + + return res; +} + + +long isdbt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + s32 res = BBM_NOK; + s32 err = 0; + s32 size = 0; + struct ISDBT_OPEN_INFO_T *hOpen; + + struct ioctl_info info; + + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) + return -EINVAL; + if (_IOC_NR(cmd) >= IOCTL_MAXNR) + return -EINVAL; + + hOpen = filp->private_data; + + size = _IOC_SIZE(cmd); + + switch (cmd) { + case IOCTL_ISDBT_RESET: + res = BBM_RESET(hInit); + break; + case IOCTL_ISDBT_INIT: + res = BBM_I2C_INIT(hInit, FCI_I2C_TYPE); + res |= BBM_PROBE(hInit); + if (res) { + PRINTF(hInit, "FC8150 Initialize Fail\n"); + break; + } + res |= BBM_INIT(hInit); + break; + case IOCTL_ISDBT_BYTE_READ: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_BYTE_READ(hInit, (u16)info.buff[0] + , (u8 *)(&info.buff[1])); + err |= copy_to_user((void *)arg, (void *)&info, size); + break; + case IOCTL_ISDBT_WORD_READ: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_WORD_READ(hInit, (u16)info.buff[0] + , (u16 *)(&info.buff[1])); + err |= copy_to_user((void *)arg, (void *)&info, size); + break; + case IOCTL_ISDBT_LONG_READ: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_LONG_READ(hInit, (u16)info.buff[0] + , (u32 *)(&info.buff[1])); + err |= copy_to_user((void *)arg, (void *)&info, size); + break; + case IOCTL_ISDBT_BULK_READ: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_BULK_READ(hInit, (u16)info.buff[0] + , (u8 *)(&info.buff[2]), info.buff[1]); + err |= copy_to_user((void *)arg, (void *)&info, size); + break; + case IOCTL_ISDBT_BYTE_WRITE: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_BYTE_WRITE(hInit, (u16)info.buff[0] + , (u8)info.buff[1]); + break; + case IOCTL_ISDBT_WORD_WRITE: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_WORD_WRITE(hInit, (u16)info.buff[0] + , (u16)info.buff[1]); + break; + case IOCTL_ISDBT_LONG_WRITE: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_LONG_WRITE(hInit, (u16)info.buff[0] + , (u32)info.buff[1]); + break; + case IOCTL_ISDBT_BULK_WRITE: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_BULK_WRITE(hInit, (u16)info.buff[0] + , (u8 *)(&info.buff[2]), info.buff[1]); + break; + case IOCTL_ISDBT_TUNER_READ: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_TUNER_READ(hInit, (u8)info.buff[0] + , (u8)info.buff[1], (u8 *)(&info.buff[3]) + , (u8)info.buff[2]); + err |= copy_to_user((void *)arg, (void *)&info, size); + break; + case IOCTL_ISDBT_TUNER_WRITE: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_TUNER_WRITE(hInit, (u8)info.buff[0] + , (u8)info.buff[1], (u8 *)(&info.buff[3]) + , (u8)info.buff[2]); + break; + case IOCTL_ISDBT_TUNER_SET_FREQ: + { + u32 f_rf; + err = copy_from_user((void *)&info, (void *)arg, size); + + f_rf = ((u32)info.buff[0] - 13) * 6000 + 473143; + res = BBM_TUNER_SET_FREQ(hInit, f_rf); + } + break; + case IOCTL_ISDBT_TUNER_SELECT: + err = copy_from_user((void *)&info, (void *)arg, size); + res = BBM_TUNER_SELECT(hInit, (u32)info.buff[0], 0); + break; + case IOCTL_ISDBT_TS_START: + hOpen->isdbttype = TS_TYPE; + break; + case IOCTL_ISDBT_TS_STOP: + hOpen->isdbttype = 0; + break; + case IOCTL_ISDBT_POWER_ON: + isdbt_hw_init(); + break; + case IOCTL_ISDBT_POWER_OFF: + isdbt_hw_deinit(); + break; + case IOCTL_ISDBT_SCAN_STATUS: + res = BBM_SCAN_STATUS(hInit); + break; + default: + PRINTF(hInit, "isdbt ioctl error!\n"); + res = BBM_NOK; + break; + } + + if (err < 0) { + PRINTF(hInit, "copy to/from user fail : %d", err); + res = BBM_NOK; + } + return res; +} + +int isdbt_init(void) +{ + s32 res; + + PRINTF(hInit, "isdbt_init\n"); + + res = misc_register(&fc8150_misc_device); + + if (res < 0) { + PRINTF(hInit, "isdbt init fail : %d\n", res); + return res; + } + + isdbt_hw_setting(); + + isdbt_hw_init(); + + hInit = kmalloc(sizeof(struct ISDBT_INIT_INFO_T), GFP_KERNEL); + + res = BBM_HOSTIF_SELECT(hInit, BBM_SPI); + + if (res) + PRINTF(hInit, "isdbt host interface select fail!\n"); + + isdbt_hw_deinit(); + + if (!isdbt_kthread) { + PRINTF(hInit, "kthread run\n"); + isdbt_kthread = kthread_run(isdbt_thread + , (void *)hInit, "isdbt_thread"); + } + + INIT_LIST_HEAD(&(hInit->hHead)); + + return 0; +} + +void isdbt_exit(void) +{ + PRINTF(hInit, "isdbt isdbt_exit\n"); + + free_irq(gpio_to_irq(GPIO_ISDBT_IRQ_FC8150), NULL); + gpio_free(GPIO_ISDBT_IRQ_FC8150); + gpio_free(GPIO_ISDBT_RST_FC8150); + gpio_free(GPIO_ISDBT_PWR_EN_FC8150); + + kthread_stop(isdbt_kthread); + isdbt_kthread = NULL; + + BBM_HOSTIF_DESELECT(hInit); + + isdbt_hw_deinit(); + + misc_deregister(&fc8150_misc_device); + + kfree(hInit); +} + +module_init(isdbt_init); +module_exit(isdbt_exit); + +MODULE_LICENSE("Dual BSD/GPL"); |