android_kernel_samsung_hero.../drivers/media/isdbt/fc8180_spi/fc8180.c
2016-08-17 16:41:52 +08:00

935 lines
24 KiB
C

/*****************************************************************************
Copyright(c) 2013 FCI Inc. All Rights Reserved
File name : fc8180.c
Description : Driver source file
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
History :
----------------------------------------------------------------------
*******************************************************************************/
#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/module.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/wakelock.h>
#include <linux/input.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include "fc8180.h"
#include "bbm.h"
#include "fci_oal.h"
#include "fci_tun.h"
#include "fc8180_regs.h"
#include "fc8180_isr.h"
#include "fci_hal.h"
#include "isdbt_tuner_pdata.h"
struct ISDBT_INIT_INFO_T *hInit;
static struct wake_lock isdbt_wlock;
int bbm_xtal_freq;
unsigned int fc8300_xtal_freq;
#define RING_BUFFER_SIZE (188 * 32 * 50)
/* GPIO(RESET & INTRRUPT) Setting */
#define FC8180_NAME "isdbt"
static struct isdbt_platform_data *isdbt_pdata;
#define TS0_32PKT_LENGTH (188 * 37) /* compatible pkt rate: 5, 37, 97, 177, 277 */
#define ISDBT_LDO_ON 1
#define ISDBT_LDO_OFF 0
u8 static_ringbuffer[RING_BUFFER_SIZE];
enum ISDBT_MODE driver_mode = ISDBT_POWEROFF;
static DEFINE_MUTEX(ringbuffer_lock);
static DEFINE_MUTEX(power_onoff_lock);
static DECLARE_WAIT_QUEUE_HEAD(isdbt_isr_wait);
#ifndef BBM_I2C_TSIF
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;
}
#endif
int isdbt_hw_setting(void)
{
int err;
pr_err("%s\n", __func__);
err = gpio_request(isdbt_pdata->gpio_en, "isdbt_en");
if (err) {
pr_err("isdbt_hw_setting: Couldn't request isdbt_en err=%d\n", err);
goto ISBT_EN_ERR;
}
gpio_direction_output(isdbt_pdata->gpio_en, 0);
#ifndef BBM_I2C_TSIF
err = gpio_request(isdbt_pdata->gpio_int, "isdbt_irq");
if (err) {
pr_err("isdbt_hw_setting: Couldn't request isdbt_irq\n");
goto ISDBT_INT_ERR;
}
gpio_direction_input(isdbt_pdata->gpio_int);
err = request_irq(gpio_to_irq(isdbt_pdata->gpio_int), isdbt_irq
, IRQF_DISABLED | IRQF_TRIGGER_FALLING, FC8180_NAME, NULL);
if (err < 0) {
print_log(0, "isdbt_hw_setting: couldn't request gpio interrupt %d reason(%d)\n"
, gpio_to_irq(isdbt_pdata->gpio_int), err);
goto request_isdbt_irq;
}
#endif
return 0;
#ifndef BBM_I2C_TSIF
request_isdbt_irq:
gpio_free(isdbt_pdata->gpio_int);
ISDBT_INT_ERR:
gpio_free(isdbt_pdata->gpio_en);
#endif
ISBT_EN_ERR:
return err;
}
static void isdbt_gpio_init(void)
{
#if defined(CONFIG_SEC_GPIO_SETTINGS)
struct pinctrl *isdbt_pinctrl;
isdbt_pinctrl = devm_pinctrl_get_select(isdbt_pdata->isdbt_device, "isdbt_gpio_suspend");
if (IS_ERR(isdbt_pinctrl)) {
pr_err("Target does not use pinctrl\n");
}
#endif
pr_err("%s\n", __func__);
isdbt_hw_setting();
}
static void isdbt_regulator_onoff(int onoff)
{
int rc = 0;
struct regulator *regulator_vdd_1p8;
if (isdbt_pdata->ldo_vdd_1p8 == NULL) {
pr_err("%s - ldo_vdd_1p8 regulator is not present. Hence ignoring the setting \n", __func__);
return;
}
if (isdbt_pdata->regulator_is_enable == onoff) {
pr_err("ISDBT duplicate regulator setting. Already in %s state", onoff ? "ON" : "OFF");
return;
}
regulator_vdd_1p8 = regulator_get(NULL, isdbt_pdata->ldo_vdd_1p8);
if (IS_ERR(regulator_vdd_1p8) || regulator_vdd_1p8 == NULL) {
pr_err("%s - ldo_vdd_1p8 regulator_get fail\n", __func__);
return;
}
pr_info("%s - onoff = %d\n", __func__, onoff);
if (onoff == ISDBT_LDO_ON) {
/* voltage setting is not allowed for LDO 23
rc = regulator_set_voltage(regulator_vdd_1p8, 1800000, 1800000);
if (rc < 0) {
pr_err("%s - set 1p8v failed, rc=%d\n",
__func__, rc);
goto done;
}
*/
rc = regulator_enable(regulator_vdd_1p8);
if (rc) {
pr_err("%s - enable vdd_1p8 failed, rc=%d\n",
__func__, rc);
goto done;
}
} else {
rc = regulator_disable(regulator_vdd_1p8);
if (rc) {
pr_err("%s - disable vdd_1p8 failed, rc=%d\n",
__func__, rc);
goto done;
}
}
isdbt_pdata->regulator_is_enable = (u8)onoff;
done:
regulator_put(regulator_vdd_1p8);
return;
}
/*POWER_ON & HW_RESET & INTERRUPT_CLEAR */
void isdbt_hw_init(void)
{
int i = 0;
#if defined(CONFIG_SEC_GPIO_SETTINGS)
struct pinctrl *isdbt_pinctrl;
isdbt_pinctrl = devm_pinctrl_get_select(isdbt_pdata->isdbt_device, "isdbt_gpio_active");
if (IS_ERR(isdbt_pinctrl)) {
pr_err("Target does not use pinctrl\n");
}
#endif
isdbt_regulator_onoff(ISDBT_LDO_ON);
clk_prepare_enable(isdbt_pdata->isdbt_clk);
pr_err("%s, Enabling ISDBT_CLK\n", __func__);
while (driver_mode == ISDBT_DATAREAD) {
ms_wait(100);
if (i++ > 5)
break;
}
pr_err("%s\n", __func__);
gpio_direction_output(isdbt_pdata->gpio_en, 1);
pr_err("%s, gpio_en =%d\n", __func__, gpio_get_value(isdbt_pdata->gpio_en));
mdelay(30);
mutex_lock(&power_onoff_lock);
driver_mode = ISDBT_POWERON;
mutex_unlock(&power_onoff_lock);
}
/*POWER_OFF */
void isdbt_hw_deinit(void)
{
#if defined(CONFIG_SEC_GPIO_SETTINGS)
struct pinctrl *isdbt_pinctrl;
#endif
mutex_lock(&power_onoff_lock);
driver_mode = ISDBT_POWEROFF;
mutex_unlock(&power_onoff_lock);
clk_disable_unprepare(isdbt_pdata->isdbt_clk);
pr_err("%s, Turning ISDBT_CLK off\n", __func__);
gpio_direction_output(isdbt_pdata->gpio_en, 0);
mdelay(5);
isdbt_regulator_onoff(ISDBT_LDO_OFF);
#if defined(CONFIG_SEC_GPIO_SETTINGS)
isdbt_pinctrl = devm_pinctrl_get_select(isdbt_pdata->isdbt_device, "isdbt_gpio_suspend");
if (IS_ERR(isdbt_pinctrl)) {
pr_err("Target does not use pinctrl\n");
}
#endif
}
int data_callback(ulong 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) {
mutex_lock(&ringbuffer_lock);
if (fci_ringbuffer_free(&hOpen->RingBuffer) < len) {
/* return 0 */;
FCI_RINGBUFFER_SKIP(&hOpen->RingBuffer, len);
}
fci_ringbuffer_write(&hOpen->RingBuffer, data, len);
wake_up_interruptible(&(hOpen->RingBuffer.queue));
mutex_unlock(&ringbuffer_lock);
}
}
return 0;
}
#ifndef BBM_I2C_TSIF
static int isdbt_thread(void *hDevice)
{
struct ISDBT_INIT_INFO_T *hInit = (struct ISDBT_INIT_INFO_T *)hDevice;
set_user_nice(current, -20);
pr_err("isdbt_kthread enter\n");
bbm_com_ts_callback_register((ulong)hInit, data_callback);
while (1) {
wait_event_interruptible(isdbt_isr_wait,
isdbt_isr_sig || kthread_should_stop());
mutex_lock(&power_onoff_lock);
if (driver_mode == ISDBT_POWERON) {
driver_mode = ISDBT_DATAREAD;
bbm_com_isr(hInit);
driver_mode = ISDBT_POWERON;
}
mutex_unlock(&power_onoff_lock);
isdbt_isr_sig = 0;
if (kthread_should_stop())
break;
}
bbm_com_ts_callback_deregister();
pr_err("isdbt_kthread exit\n");
return 0;
}
#endif
const struct file_operations isdbt_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = isdbt_ioctl,
.open = isdbt_open,
.read = isdbt_read,
.release = isdbt_release,
#ifdef CONFIG_COMPAT
.compat_ioctl = isdbt_ioctl,
#endif
};
static struct miscdevice fc8180_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = FC8180_NAME,
.fops = &isdbt_fops,
};
int isdbt_open(struct inode *inode, struct file *filp)
{
struct ISDBT_OPEN_INFO_T *hOpen;
pr_err("isdbt open\n");
hOpen = kmalloc(sizeof(struct ISDBT_OPEN_INFO_T), GFP_KERNEL);
if (!hOpen) {
pr_err("ISDBT hOpen malloc failed ENOMEM\n");
return -ENOMEM;
}
hOpen->buf = &static_ringbuffer[0];
/*kmalloc(RING_BUFFER_SIZE, GFP_KERNEL);*/
hOpen->isdbttype = 0;
list_add(&(hOpen->hList), &(hInit->hHead));
hOpen->hInit = (HANDLE *)hInit;
if (hOpen->buf == NULL) {
pr_err("ISDBT ring buffer malloc error\n");
return -ENOMEM;
}
fci_ringbuffer_init(&hOpen->RingBuffer, hOpen->buf, RING_BUFFER_SIZE);
filp->private_data = hOpen;
wake_lock(&isdbt_wlock);
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, read_len = 0;
if (!cibuf->data || !count) {
/*pr_err(" return 0\n"); */
return 0;
}
if (non_blocking && (fci_ringbuffer_empty(cibuf))) {
/*pr_err("return EWOULDBLOCK\n"); */
return -EWOULDBLOCK;
}
if (wait_event_interruptible(cibuf->queue,
!fci_ringbuffer_empty(cibuf))) {
pr_err("return ERESTARTSYS\n");
return -ERESTARTSYS;
}
mutex_lock(&ringbuffer_lock);
avail = fci_ringbuffer_avail(cibuf);
if (count >= avail)
len = avail;
else
len = count - (count % 188);
read_len = fci_ringbuffer_read_user(cibuf, buf, len);
mutex_unlock(&ringbuffer_lock);
return read_len;
}
int isdbt_release(struct inode *inode, struct file *filp)
{
struct ISDBT_OPEN_INFO_T *hOpen;
pr_err("isdbt_release\n");
hOpen = filp->private_data;
if (hOpen != NULL) {
hOpen->isdbttype = 0;
list_del(&(hOpen->hList));
pr_err("isdbt_release hList\n");
/*kfree(hOpen->buf);*/
kfree(hOpen);
wake_unlock(&isdbt_wlock);
}
if (isdbt_pdata->regulator_is_enable)
isdbt_regulator_onoff(ISDBT_LDO_OFF);
return 0;
}
#ifndef BBM_I2C_TSIF
void isdbt_isr_check(HANDLE hDevice)
{
u8 isr_time = 0;
bbm_com_write(hDevice, BBM_BUF_ENABLE, 0x00);
while (isr_time < 10) {
if (!isdbt_isr_sig)
break;
ms_wait(10);
isr_time++;
}
}
#endif
static ssize_t isdbt_ber_show(struct class *dev,
struct class_attribute *attr, char *buf)
{
int type = 0;
sprintf(buf, "%d,%d", type, isdbt_pdata->BER);
pr_info("%s, type:%d, ber:%d\n", __func__, type, isdbt_pdata->BER);
return strlen(buf);
}
static CLASS_ATTR(ber, 0444,
isdbt_ber_show, NULL);
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_com_reset(hInit);
pr_err("[FC8180] IOCTL_ISDBT_RESET\n");
break;
case IOCTL_ISDBT_INIT:
pr_err("[FC8180] IOCTL_ISDBT_INIT\n");
res = bbm_com_i2c_init(hInit, FCI_HPI_TYPE);
pr_err("[FC8180] IOCTL_ISDBT_INIT bbm_com_i2c_init res =%d\n", res);
res |= bbm_com_probe(hInit);
if (res) {
pr_err("FC8180 Initialize Fail\n");
break;
}
pr_err("[FC8180] IOCTL_ISDBT_INIT bbm_com_probe success\n");
res = bbm_com_init(hInit);
pr_err("[FC8180] IOCTL_ISDBT_INITbbm_com_init\n");
res |= bbm_com_tuner_select(hInit, FC8180_TUNER, 0);
break;
case IOCTL_ISDBT_BYTE_READ:
err = copy_from_user((void *)&info, (void *)arg, size);
res = bbm_com_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_com_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_com_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_com_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_com_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_com_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_com_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_com_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_com_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_com_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];
pr_err("[FC8180] IOCTL_ISDBT_TUNER_SET_FREQ freq=%d\n", f_rf);
#ifndef BBM_I2C_TSIF
isdbt_isr_check(hInit);
#endif
res = bbm_com_tuner_set_freq(hInit, f_rf);
#ifndef BBM_I2C_TSIF
mutex_lock(&ringbuffer_lock);
fci_ringbuffer_flush(&hOpen->RingBuffer);
mutex_unlock(&ringbuffer_lock);
bbm_com_write(hInit, BBM_BUF_ENABLE, 0x01);
#endif
}
break;
case IOCTL_ISDBT_TUNER_SELECT:
pr_err("[FC8180] IOCTL_ISDBT_TUNER_SELECT\n");
err = copy_from_user((void *)&info, (void *)arg, size);
res = bbm_com_tuner_select(hInit
, (u32)info.buff[0], (u32)info.buff[1]);
bbm_com_byte_write(hInit, BBM_BUF_ENABLE, 0x00);
bbm_com_word_write(hInit, BBM_BUF_TS_END, (TS0_32PKT_LENGTH * 2) - 1);
bbm_com_word_write(hInit, BBM_BUF_TS_THR, (TS0_32PKT_LENGTH - 1));
bbm_com_byte_write(hInit, BBM_BUF_ENABLE, 0x01);
print_log(hInit, "[FC8180] IOCTL_ISDBT_TUNER_SELECT %d\n"
, (u32)info.buff[1]);
break;
case IOCTL_ISDBT_RF_BER:
err = copy_from_user((void *)&info, (void *)arg, size);
pr_err("[FC8300] IOCTL_ISDBT_RF_BER, CN(%d), BER_A(%d), BER_B(%d)\n",
(u8)info.buff[0], (u32)info.buff[1], (u32)info.buff[2]);
isdbt_pdata->BER = (int)info.buff[1];
res = 0;
break;
case IOCTL_ISDBT_TS_START:
pr_err("[FC8180] IOCTL_ISDBT_TS_START\n");
hOpen->isdbttype = TS_TYPE;
break;
case IOCTL_ISDBT_TS_STOP:
pr_err("[FC8180] IOCTL_ISDBT_TS_STOP\n");
hOpen->isdbttype = 0;
break;
case IOCTL_ISDBT_POWER_ON:
pr_err("[FC8180] IOCTL_ISDBT_POWER_ON\n");
isdbt_hw_init();
#ifdef BBM_SPI_IF
bbm_com_byte_write(hInit, BBM_DM_DATA, 0x00);
#endif
res = bbm_com_i2c_init(hInit, FCI_HPI_TYPE);
pr_err("[FC8180] IOCTL_ISDBT_POWER_ON bbm_com_i2c_init res =%d\n", res);
res |= bbm_com_probe(hInit);
if (res) {
pr_err("FC8180 Initialize Fail\n");
isdbt_hw_deinit();
} else {
pr_err("FC8180 IOCTL_ISDBT_POWER_ON SUCCESS\n");
}
break;
case IOCTL_ISDBT_POWER_OFF:
pr_err("[FC8180] IOCTL_ISDBT_POWER_OFF\n");
isdbt_hw_deinit();
break;
case IOCTL_ISDBT_SCAN_STATUS:
res = bbm_com_scan_status(hInit);
pr_err("[FC8180] IOCTL_ISDBT_SCAN_STATUS : %d\n", res);
break;
case IOCTL_ISDBT_TUNER_GET_RSSI:
err = copy_from_user((void *)&info, (void *)arg, size);
res = bbm_com_tuner_get_rssi(hInit, (s32 *)&info.buff[0]);
err |= copy_to_user((void *)arg, (void *)&info, size);
break;
default:
pr_err("isdbt ioctl error!\n");
res = BBM_NOK;
break;
}
if (err < 0) {
pr_err("copy to/from user fail : %d", err);
res = BBM_NOK;
}
return res;
}
static struct isdbt_platform_data *isdbt_populate_dt_pdata(struct device *dev)
{
struct isdbt_platform_data *pdata;
const char *temp_string = NULL;
int ret = 0;
pr_err("%s\n", __func__);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
pr_err("%s : could not allocate memory for platform data\n", __func__);
goto err;
}
of_property_read_u32(dev->of_node, "isdbt,isdb-bbm-xtal-freq", &bbm_xtal_freq);
if (bbm_xtal_freq < 0) {
pr_err("%s : can not find the isdbt-bbmxtal-freq in the dt, set to : 26000\n", __func__);
bbm_xtal_freq = 26000;
}
pr_err("%s : bbm_xtal_freq :%d\n", __func__, bbm_xtal_freq);
pdata->gpio_en = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-pwr-en", 0);
if (pdata->gpio_en < 0)
of_property_read_u32(dev->of_node, "isdbt,isdb-gpio-pwr-en", &pdata->gpio_en);
if (pdata->gpio_en < 0) {
pr_err("%s : can not find the isdbt-detect-gpio gpio_en in the dt\n", __func__);
goto alloc_err;
} else {
pr_err("%s : isdbt-detect-gpio gpio_en =%d\n", __func__, pdata->gpio_en);
}
#ifndef BBM_I2C_TSIF
pdata->gpio_int = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-irq", 0);
if (pdata->gpio_int < 0)
of_property_read_u32(dev->of_node, "isdbt,isdb-gpio-irq", &pdata->gpio_int);
if (pdata->gpio_int < 0) {
pr_err("%s : can not find the isdbt-detect-gpio in the gpio_int dt\n", __func__);
goto alloc_err;
} else {
pr_err("%s : isdbt-detect-gpio gpio_int =%d\n", __func__, pdata->gpio_int);
}
#endif
pdata->gpio_i2c_sda = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-i2c_sda", 0);
if (pdata->gpio_i2c_sda < 0)
of_property_read_u32(dev->of_node, "isdbt,isdb-gpio-i2c_sda", &pdata->gpio_i2c_sda);
if (pdata->gpio_i2c_sda < 0) {
pr_err("%s : can not find the isdbt-detect-gpio gpio_i2c_sda in the dt\n", __func__);
/* goto alloc_err; */
} else {
pr_err("%s : isdbt-detect-gpio gpio_i2c_sda=%d\n", __func__, pdata->gpio_i2c_sda);
}
pdata->gpio_i2c_scl = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-i2c_scl", 0);
if (pdata->gpio_i2c_scl < 0)
of_property_read_u32(dev->of_node, "isdbt,isdb-gpio-i2c_scl", &pdata->gpio_i2c_scl);
if (pdata->gpio_i2c_scl < 0) {
pr_err("%s : can not find the isdbt-detect-gpio gpio_i2c_scl in the dt\n", __func__);
/* goto alloc_err; */
} else {
pr_err("%s : isdbt-detect-gpio gpio_i2c_scl=%d\n", __func__, pdata->gpio_i2c_scl);
}
pdata->gpio_spi_do = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-spi_do", 0);
if (pdata->gpio_spi_do < 0) {
pr_err("%s : can not find the isdbt-detect-gpio in the gpio_spi_do dt\n", __func__);
goto alloc_err;
} else
pr_err("%s : isdbt-detect-gpio gpio_spi_do =%d\n", __func__, pdata->gpio_spi_do);
pdata->gpio_spi_di = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-spi_di", 0);
if (pdata->gpio_spi_di < 0) {
pr_err("%s : can not find the isdbt-detect-gpio in the gpio_spi_di dt\n", __func__);
goto alloc_err;
} else
pr_err("%s : isdbt-detect-gpio gpio_spi_di =%d\n", __func__, pdata->gpio_spi_di);
pdata->gpio_spi_cs = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-spi_cs", 0);
if (pdata->gpio_spi_cs < 0) {
pr_err("%s : can not find the isdbt-detect-gpio gpio_spi_cs in the dt\n", __func__);
goto alloc_err;
} else
pr_err("%s : isdbt-detect-gpio gpio_spi_cs=%d\n", __func__, pdata->gpio_spi_cs);
pdata->gpio_spi_clk = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-spi_clk", 0);
if (pdata->gpio_spi_clk < 0) {
pr_err("%s : can not find the isdbt-detect-gpio gpio_spi_clk in the dt\n", __func__);
goto alloc_err;
} else
pr_err("%s : isdbt-detect-gpio gpio_spi_clk=%d\n", __func__, pdata->gpio_spi_clk);
ret = of_property_read_string(dev->of_node, "clock-names", &temp_string);
if (ret)
pr_err("isdbt : %s: cannot get clock name(%d)", __func__, ret);
pdata->isdbt_clk = clk_get(dev, temp_string);
if (pdata->isdbt_clk < 0)
pr_err("isdbt : %s: cannot get clock", __func__);
if (of_property_read_string(dev->of_node, "isdbt,ldo_vdd_1p8",
&pdata->ldo_vdd_1p8) < 0)
pr_err("%s - get ldo_vdd_1p8 error\n", __func__);
return pdata;
alloc_err:
devm_kfree(dev, pdata);
err:
return NULL;
}
static int isdbt_probe(struct platform_device *pdev)
{
int res = 0;
static struct class *isdbt_class;
pr_err("%s\n", __func__);
isdbt_pdata = isdbt_populate_dt_pdata(&pdev->dev);
if (!isdbt_pdata) {
pr_err("%s : isdbt_pdata is NULL.\n", __func__);
return -ENODEV;
}
#if defined(CONFIG_SEC_GPIO_SETTINGS)
/* Get pinctrl if target uses pinctrl */
isdbt_pdata->isdbt_device = &pdev->dev;
#endif
isdbt_gpio_init();
fc8300_xtal_freq = bbm_xtal_freq;
res = misc_register(&fc8180_misc_device);
if (res < 0) {
pr_err("isdbt init fail : %d\n", res);
return res;
}
hInit = kmalloc(sizeof(struct ISDBT_INIT_INFO_T), GFP_KERNEL);
#if defined(BBM_I2C_TSIF) || defined(BBM_I2C_SPI)
res = bbm_com_hostif_select(hInit, BBM_I2C);
pr_err("isdbt host interface select BBM_I2C!\n");
#else
pr_err("isdbt host interface select BBM_SPI !\n");
res = bbm_com_hostif_select(hInit, BBM_SPI);
#endif
if (res)
pr_err("isdbt host interface select fail!\n");
#ifndef BBM_I2C_TSIF
if (!isdbt_kthread) {
pr_err("kthread run\n");
isdbt_kthread = kthread_run(isdbt_thread
, (void *)hInit, "isdbt_thread");
}
#endif
INIT_LIST_HEAD(&(hInit->hHead));
isdbt_class = class_create(THIS_MODULE, "isdbt");
if (IS_ERR(isdbt_class)) {
pr_err("%s : class_create failed!\n", __func__);
} else {
res = class_create_file(isdbt_class, &class_attr_ber);
if (res)
pr_err("%s : failed to create device file in sysfs entries!\n", __func__);
}
wake_lock_init(&isdbt_wlock, WAKE_LOCK_SUSPEND, "isdbt_wlock");
return 0;
}
static int isdbt_remove(struct platform_device *pdev)
{
pr_err("ISDBT remove\n");
wake_lock_destroy(&isdbt_wlock);
return 0;
}
static int isdbt_suspend(struct platform_device *pdev, pm_message_t mesg)
{
int value;
value = gpio_get_value_cansleep(isdbt_pdata->gpio_en);
pr_err("%s value = %d\n", __func__, value);
if (value == 1)
gpio_direction_output(isdbt_pdata->gpio_en, 0);
return 0;
}
static int isdbt_resume(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id isdbt_match_table[] = {
{ .compatible = "isdbt_pdata",
},
{}
};
static struct platform_driver isdb_fc8180_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "isdbt",
.of_match_table = isdbt_match_table,
},
.probe = isdbt_probe,
.remove = isdbt_remove,
.suspend = isdbt_suspend,
.resume = isdbt_resume,
};
int isdbt_init(void)
{
s32 res;
pr_err("isdbt_fc8180_init started\n");
/* print_log(hInit, "isdbt_init 20150603\n"); */
res = platform_driver_register(&isdb_fc8180_driver);
if (res < 0) {
pr_err("isdbt init fail : %d\n", res);
return res;
}
return 0;
}
void isdbt_exit(void)
{
pr_err("isdb_fc8300_exit\n");
#ifndef BBM_I2C_TSIF
free_irq(gpio_to_irq(isdbt_pdata->gpio_int), NULL);
gpio_free(isdbt_pdata->gpio_int);
#endif
gpio_free(isdbt_pdata->gpio_en);
#ifndef BBM_I2C_TSIF
if (isdbt_kthread)
kthread_stop(isdbt_kthread);
isdbt_kthread = NULL;
#endif
bbm_com_hostif_deselect(hInit);
isdbt_hw_deinit();
platform_driver_unregister(&isdb_fc8180_driver);
misc_deregister(&fc8180_misc_device);
if (hInit != NULL)
kfree(hInit);
}
module_init(isdbt_init);
module_exit(isdbt_exit);
MODULE_LICENSE("Dual BSD/GPL");