mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-25 14:13:01 -04:00
radio: RTC6226: Make the rtc6226 driver compatible with QTI platform
Moved the power on functionality under set control ioctl. Removed the blocker code for tune, seek operation. Added code for posting event to user space as part of interrupt handling. Add support to power on/off rtc6226 chip and enable. CRs-Fixed: 2525362 Change-Id: I61cea2d59a57ae7395971c7f8493582abedf5038 Signed-off-by: himta ram <hram@codeaurora.org>
This commit is contained in:
parent
12db9c0b36
commit
087c5f204e
4 changed files with 712 additions and 518 deletions
|
|
@ -508,7 +508,7 @@ endif # V4L_RADIO_ISA_DRIVERS
|
|||
|
||||
config I2C_RTC6226_QCA
|
||||
tristate "Richwave RTC6226 FM Radio Receiver support with I2C for QCA"
|
||||
depends on I2C && RADIO_RTC6226_QCA
|
||||
depends on I2C && VIDEO_V4L2
|
||||
---help---
|
||||
This is a driver for I2C devices with the Richwave RTC6226
|
||||
chip.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -179,7 +179,7 @@ int rtc6226_get_all_registers(struct rtc6226_device *radio)
|
|||
int i;
|
||||
int err;
|
||||
u8 reg[1] = {0x00};
|
||||
u8 buf[RADIO_REGISTER_NUM * 2];
|
||||
u8 buf[RADIO_REGISTER_NUM];
|
||||
struct i2c_msg msgs1[1] = {
|
||||
{ radio->client->addr, 0, 1, reg},
|
||||
};
|
||||
|
|
@ -208,7 +208,7 @@ int rtc6226_get_all_registers(struct rtc6226_device *radio)
|
|||
int rtc6226_vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *capability)
|
||||
{
|
||||
pr_info("%s enter\n", __func__);
|
||||
FMDBG("%s enter\n", __func__);
|
||||
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
|
||||
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
|
||||
capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
|
||||
|
|
@ -226,47 +226,81 @@ static void rtc6226_i2c_interrupt_handler(struct rtc6226_device *radio)
|
|||
{
|
||||
unsigned char regnr;
|
||||
int retval = 0;
|
||||
unsigned short current_chan;
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
FMDBG("%s enter\n", __func__);
|
||||
|
||||
/* check Seek/Tune Complete */
|
||||
retval = rtc6226_get_register(radio, STATUS);
|
||||
if (retval < 0) {
|
||||
pr_err("%s read fail to STATUS\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
retval = rtc6226_get_register(radio, RSSI);
|
||||
if (retval < 0) {
|
||||
pr_err("%s read fail to RSSI\n", __func__);
|
||||
FMDERR("%s read fail to STATUS\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (radio->registers[STATUS] & STATUS_STD) {
|
||||
complete(&radio->completion);
|
||||
pr_info("%s Seek/Tune Done\n", __func__);
|
||||
}
|
||||
FMDBG("%s : STATUS=0x%4.4hx\n", __func__,
|
||||
radio->registers[STATUS]);
|
||||
|
||||
/* Update RDS registers */
|
||||
for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) {
|
||||
retval = rtc6226_get_register(radio, STATUS + regnr);
|
||||
if (retval < 0)
|
||||
retval = rtc6226_get_register(radio, RSSI);
|
||||
if (retval < 0) {
|
||||
FMDERR("%s read fail to RSSI\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* get rds blocks */
|
||||
if ((radio->registers[STATUS] & STATUS_RDS_RDY) == 0) {
|
||||
/* No RDS group ready, better luck next time */
|
||||
pr_err("%s No RDS group ready\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
FMDBG("%s : RSSI=0x%4.4hx\n", __func__, radio->registers[RSSI]);
|
||||
/* stop seeking : clear STD*/
|
||||
radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEK;
|
||||
retval = rtc6226_set_register(radio, SEEKCFG1);
|
||||
/*clear the status bit to allow another tune or seek*/
|
||||
current_chan = radio->registers[CHANNEL] & CHANNEL_CSR0_CH;
|
||||
radio->registers[CHANNEL] &= ~CHANNEL_CSR0_TUNE;
|
||||
retval = rtc6226_set_register(radio, CHANNEL);
|
||||
if (retval < 0)
|
||||
radio->registers[CHANNEL] = current_chan;
|
||||
rtc6226_reset_rds_data(radio);
|
||||
FMDBG("%s clear Seek/Tune bit\n", __func__);
|
||||
if (radio->seek_tune_status == SEEK_PENDING) {
|
||||
FMDBG("posting RTC6226_EVT_SEEK_COMPLETE event\n");
|
||||
rtc6226_q_event(radio, RTC6226_EVT_SEEK_COMPLETE);
|
||||
/* post tune comp evt since seek results in a tune.*/
|
||||
FMDBG("posting RICHWAVE_EVT_TUNE_SUCC event\n");
|
||||
rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC);
|
||||
radio->seek_tune_status = NO_SEEK_TUNE_PENDING;
|
||||
} else if (radio->seek_tune_status == TUNE_PENDING) {
|
||||
FMDBG("posting RICHWAVE_EVT_TUNE_SUCC event\n");
|
||||
rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC);
|
||||
radio->seek_tune_status = NO_SEEK_TUNE_PENDING;
|
||||
} else if (radio->seek_tune_status == SCAN_PENDING) {
|
||||
/* when scan is pending and STC int is set, signal
|
||||
* so that scan can proceed
|
||||
*/
|
||||
FMDBG("In %s, signalling scan thread\n", __func__);
|
||||
complete(&radio->completion);
|
||||
}
|
||||
FMDBG("%s Seek/Tune done\n", __func__);
|
||||
} else {
|
||||
/* Check RDS data after tune/seek interrupt finished
|
||||
* Update RDS registers
|
||||
*/
|
||||
for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) {
|
||||
retval = rtc6226_get_register(radio, STATUS + regnr);
|
||||
if (retval < 0)
|
||||
goto end;
|
||||
}
|
||||
/* get rds blocks */
|
||||
if ((radio->registers[STATUS] & STATUS_RDS_RDY) == 0) {
|
||||
/* No RDS group ready, better luck next time */
|
||||
FMDERR("%s No RDS group ready\n", __func__);
|
||||
goto end;
|
||||
} else {
|
||||
/* avoid RDS interrupt lock disable_irq*/
|
||||
if ((radio->registers[SYSCFG] & SYSCFG_CSR0_RDS_EN) != 0) {
|
||||
pr_info("%s start rds handler\n", __func__);
|
||||
schedule_work(&radio->rds_worker);
|
||||
if ((radio->registers[SYSCFG] &
|
||||
SYSCFG_CSR0_RDS_EN) != 0) {
|
||||
schedule_work(&radio->rds_worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
pr_info("%s exit :%d\n", __func__, retval);
|
||||
FMDBG("%s exit :%d\n", __func__, retval);
|
||||
}
|
||||
|
||||
static irqreturn_t rtc6226_isr(int irq, void *dev_id)
|
||||
|
|
@ -319,7 +353,7 @@ int rtc6226_enable_irq(struct rtc6226_device *radio)
|
|||
|
||||
retval = gpio_direction_input(radio->int_gpio);
|
||||
if (retval) {
|
||||
pr_err("%s unable to set the gpio %d direction(%d)\n",
|
||||
FMDERR("%s unable to set the gpio %d direction(%d)\n",
|
||||
__func__, radio->int_gpio, retval);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -327,25 +361,25 @@ int rtc6226_enable_irq(struct rtc6226_device *radio)
|
|||
irq = radio->irq;
|
||||
|
||||
if (radio->irq < 0) {
|
||||
pr_err("%s: gpio_to_irq returned %d\n", __func__, radio->irq);
|
||||
FMDERR("%s: gpio_to_irq returned %d\n", __func__, radio->irq);
|
||||
goto open_err_req_irq;
|
||||
}
|
||||
|
||||
pr_info("%s irq number is = %d\n", __func__, radio->irq);
|
||||
FMDBG("%s irq number is = %d\n", __func__, radio->irq);
|
||||
|
||||
retval = request_any_context_irq(radio->irq, rtc6226_isr,
|
||||
IRQF_TRIGGER_FALLING, DRIVER_NAME, radio);
|
||||
|
||||
if (retval < 0) {
|
||||
pr_err("%s Couldn't acquire FM gpio %d, retval:%d\n",
|
||||
FMDERR("%s Couldn't acquire FM gpio %d, retval:%d\n",
|
||||
__func__, radio->irq, retval);
|
||||
goto open_err_req_irq;
|
||||
} else {
|
||||
pr_info("%s FM GPIO %d registered\n", __func__, radio->irq);
|
||||
FMDBG("%s FM GPIO %d registered\n", __func__, radio->irq);
|
||||
}
|
||||
retval = enable_irq_wake(irq);
|
||||
if (retval < 0) {
|
||||
pr_err("Could not wake FM interrupt\n");
|
||||
FMDERR("Could not wake FM interrupt\n");
|
||||
free_irq(irq, radio);
|
||||
}
|
||||
return retval;
|
||||
|
|
@ -356,6 +390,133 @@ open_err_req_irq:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int rtc6226_fm_vio_reg_cfg(struct rtc6226_device *radio, bool on)
|
||||
{
|
||||
int rc = 0;
|
||||
struct fm_power_vreg_data *vreg;
|
||||
|
||||
vreg = radio->vioreg;
|
||||
if (!vreg) {
|
||||
FMDERR("In %s, vio reg is NULL\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
if (on) {
|
||||
FMDBG("vreg is : %s\n", vreg->name);
|
||||
rc = regulator_set_voltage(vreg->reg,
|
||||
vreg->low_vol_level,
|
||||
vreg->high_vol_level);
|
||||
if (rc < 0) {
|
||||
FMDERR("set_vol(%s) fail %d\n", vreg->name, rc);
|
||||
return rc;
|
||||
}
|
||||
rc = regulator_enable(vreg->reg);
|
||||
if (rc < 0) {
|
||||
FMDERR("reg enable(%s) failed.rc=%d\n", vreg->name, rc);
|
||||
regulator_set_voltage(vreg->reg,
|
||||
0,
|
||||
vreg->high_vol_level);
|
||||
return rc;
|
||||
}
|
||||
vreg->is_enabled = true;
|
||||
|
||||
} else {
|
||||
rc = regulator_disable(vreg->reg);
|
||||
if (rc < 0) {
|
||||
FMDERR("reg disable(%s) fail rc=%d\n", vreg->name, rc);
|
||||
return rc;
|
||||
}
|
||||
vreg->is_enabled = false;
|
||||
|
||||
/* Set the min voltage to 0 */
|
||||
rc = regulator_set_voltage(vreg->reg,
|
||||
0,
|
||||
vreg->high_vol_level);
|
||||
if (rc < 0) {
|
||||
FMDERR("set_vol(%s) fail %d\n", vreg->name, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rtc6226_fm_vdd_reg_cfg(struct rtc6226_device *radio, bool on)
|
||||
{
|
||||
int rc = 0;
|
||||
struct fm_power_vreg_data *vreg;
|
||||
|
||||
vreg = radio->vddreg;
|
||||
if (!vreg) {
|
||||
FMDERR("In %s, vdd reg is NULL\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (on) {
|
||||
FMDBG("vreg is : %s\n", vreg->name);
|
||||
rc = regulator_set_voltage(vreg->reg,
|
||||
vreg->low_vol_level,
|
||||
vreg->high_vol_level);
|
||||
if (rc < 0) {
|
||||
FMDERR("set_vol(%s) fail %d\n", vreg->name, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = regulator_enable(vreg->reg);
|
||||
if (rc < 0) {
|
||||
FMDERR("reg enable(%s) failed.rc=%d\n", vreg->name, rc);
|
||||
regulator_set_voltage(vreg->reg,
|
||||
0,
|
||||
vreg->high_vol_level);
|
||||
return rc;
|
||||
}
|
||||
vreg->is_enabled = true;
|
||||
} else {
|
||||
rc = regulator_disable(vreg->reg);
|
||||
if (rc < 0) {
|
||||
FMDERR("reg disable(%s) fail. rc=%d\n", vreg->name, rc);
|
||||
return rc;
|
||||
}
|
||||
vreg->is_enabled = false;
|
||||
|
||||
/* Set the min voltage to 0 */
|
||||
rc = regulator_set_voltage(vreg->reg,
|
||||
0,
|
||||
vreg->high_vol_level);
|
||||
if (rc < 0) {
|
||||
FMDERR("set_vol(%s) fail %d\n", vreg->name, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rtc6226_fm_power_cfg(struct rtc6226_device *radio, bool powerflag)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (powerflag) {
|
||||
/* Turn ON sequence */
|
||||
rc = rtc6226_fm_vdd_reg_cfg(radio, powerflag);
|
||||
if (rc < 0) {
|
||||
FMDERR("In %s, vdd reg cfg failed %x\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
rc = rtc6226_fm_vio_reg_cfg(radio, powerflag);
|
||||
if (rc < 0) {
|
||||
FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc);
|
||||
rtc6226_fm_vdd_reg_cfg(radio, false);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
/* Turn OFF sequence */
|
||||
rc = rtc6226_fm_vdd_reg_cfg(radio, powerflag);
|
||||
if (rc < 0)
|
||||
FMDERR("In %s, vdd reg cfg failed %x\n", __func__, rc);
|
||||
rc = rtc6226_fm_vio_reg_cfg(radio, powerflag);
|
||||
if (rc < 0)
|
||||
FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
/*
|
||||
* rtc6226_fops_open - file open
|
||||
*/
|
||||
|
|
@ -363,42 +524,43 @@ int rtc6226_fops_open(struct file *file)
|
|||
{
|
||||
struct rtc6226_device *radio = video_drvdata(file);
|
||||
int retval = v4l2_fh_open(file);
|
||||
int i;
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
FMDBG("%s enter user num = %d\n", __func__, radio->users);
|
||||
if (retval) {
|
||||
pr_err("%s fail to open v4l2\n", __func__);
|
||||
FMDERR("%s fail to open v4l2\n", __func__);
|
||||
return retval;
|
||||
}
|
||||
if (atomic_inc_return(&radio->users) != 1) {
|
||||
FMDERR("Device already in use. Try again later\n");
|
||||
atomic_dec(&radio->users);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&radio->work, rtc6226_handler);
|
||||
INIT_DELAYED_WORK(&radio->work_scan, rtc6226_scan);
|
||||
INIT_WORK(&radio->rds_worker, rtc6226_rds_handler);
|
||||
|
||||
if (v4l2_fh_is_singular_file(file)) {
|
||||
retval = rtc6226_power_up(radio);
|
||||
if (retval < 0) {
|
||||
pr_err("%s fail to power_up\n", __func__);
|
||||
goto done;
|
||||
//return retval;
|
||||
}
|
||||
/* Power up Supply voltage to VDD and VIO */
|
||||
retval = rtc6226_fm_power_cfg(radio, TURNING_ON);
|
||||
if (retval) {
|
||||
FMDERR("%s: failed to supply voltage\n", __func__);
|
||||
goto open_err_setup;
|
||||
}
|
||||
|
||||
retval = rtc6226_get_all_registers(radio);
|
||||
if (retval < 0)
|
||||
pr_err("%s fail to get register %d\n", __func__, retval);
|
||||
else {
|
||||
for (i = 0; i < 16; i++)
|
||||
pr_info("%s registers[%d]:%x\n", __func__, i,
|
||||
radio->registers[i]);
|
||||
}
|
||||
retval = rtc6226_enable_irq(radio);
|
||||
/* Wait for the value to take effect on gpio. */
|
||||
msleep(100);
|
||||
rtc6226_enable_irq(radio);
|
||||
if (retval) {
|
||||
FMDERR("%s:enable irq failed\n", __func__);
|
||||
goto open_err_req_irq;
|
||||
}
|
||||
return retval;
|
||||
|
||||
done:
|
||||
if (retval)
|
||||
v4l2_fh_release(file);
|
||||
open_err_req_irq:
|
||||
rtc6226_fm_power_cfg(radio, TURNING_OFF);
|
||||
open_err_setup:
|
||||
atomic_dec(&radio->users);
|
||||
v4l2_fh_release(file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -408,8 +570,9 @@ done:
|
|||
int rtc6226_fops_release(struct file *file)
|
||||
{
|
||||
struct rtc6226_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
pr_info("%s : Exit\n", __func__);
|
||||
FMDBG("%s : Exit\n", __func__);
|
||||
if (v4l2_fh_is_singular_file(file)) {
|
||||
if (radio->mode != FM_OFF) {
|
||||
rtc6226_power_down(radio);
|
||||
|
|
@ -417,6 +580,10 @@ int rtc6226_fops_release(struct file *file)
|
|||
}
|
||||
}
|
||||
rtc6226_disable_irq(radio);
|
||||
atomic_dec(&radio->users);
|
||||
retval = rtc6226_fm_power_cfg(radio, TURNING_OFF);
|
||||
if (retval < 0)
|
||||
FMDERR("%s: failed to apply voltage\n", __func__);
|
||||
return v4l2_fh_release(file);
|
||||
}
|
||||
|
||||
|
|
@ -428,21 +595,21 @@ static int rtc6226_parse_dt(struct device *dev,
|
|||
|
||||
radio->int_gpio = of_get_named_gpio(np, "fmint-gpio", 0);
|
||||
if (radio->int_gpio < 0) {
|
||||
pr_err("%s int-gpio not provided in device tree\n", __func__);
|
||||
FMDERR("%s int-gpio not provided in device tree\n", __func__);
|
||||
rc = radio->int_gpio;
|
||||
goto err_int_gpio;
|
||||
}
|
||||
|
||||
rc = gpio_request(radio->int_gpio, "fm_int");
|
||||
if (rc) {
|
||||
pr_err("%s unable to request gpio %d (%d)\n", __func__,
|
||||
FMDERR("%s unable to request gpio %d (%d)\n", __func__,
|
||||
radio->int_gpio, rc);
|
||||
goto err_int_gpio;
|
||||
}
|
||||
|
||||
rc = gpio_direction_output(radio->int_gpio, 0);
|
||||
if (rc) {
|
||||
pr_err("%s unable to set the gpio %d direction(%d)\n",
|
||||
FMDERR("%s unable to set the gpio %d direction(%d)\n",
|
||||
__func__, radio->int_gpio, rc);
|
||||
goto err_int_gpio;
|
||||
}
|
||||
|
|
@ -463,7 +630,7 @@ static int rtc6226_pinctrl_init(struct rtc6226_device *radio)
|
|||
|
||||
radio->fm_pinctrl = devm_pinctrl_get(&radio->client->dev);
|
||||
if (IS_ERR_OR_NULL(radio->fm_pinctrl)) {
|
||||
pr_err("%s: target does not use pinctrl\n", __func__);
|
||||
FMDERR("%s: target does not use pinctrl\n", __func__);
|
||||
retval = PTR_ERR(radio->fm_pinctrl);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -472,7 +639,7 @@ static int rtc6226_pinctrl_init(struct rtc6226_device *radio)
|
|||
pinctrl_lookup_state(radio->fm_pinctrl,
|
||||
"pmx_fm_active");
|
||||
if (IS_ERR_OR_NULL(radio->gpio_state_active)) {
|
||||
pr_err("%s: cannot get FM active state\n", __func__);
|
||||
FMDERR("%s: cannot get FM active state\n", __func__);
|
||||
retval = PTR_ERR(radio->gpio_state_active);
|
||||
goto err_active_state;
|
||||
}
|
||||
|
|
@ -481,7 +648,7 @@ static int rtc6226_pinctrl_init(struct rtc6226_device *radio)
|
|||
pinctrl_lookup_state(radio->fm_pinctrl,
|
||||
"pmx_fm_suspend");
|
||||
if (IS_ERR_OR_NULL(radio->gpio_state_suspend)) {
|
||||
pr_err("%s: cannot get FM suspend state\n", __func__);
|
||||
FMDERR("%s: cannot get FM suspend state\n", __func__);
|
||||
retval = PTR_ERR(radio->gpio_state_suspend);
|
||||
goto err_suspend_state;
|
||||
}
|
||||
|
|
@ -497,6 +664,23 @@ err_active_state:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int rtc6226_dt_parse_vreg_info(struct device *dev,
|
||||
struct fm_power_vreg_data *vreg, const char *vreg_name)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 vol_suply[2];
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
ret = of_property_read_u32_array(np, vreg_name, vol_suply, 2);
|
||||
if (ret < 0) {
|
||||
FMDERR("Invalid property name\n");
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
vreg->low_vol_level = vol_suply[0];
|
||||
vreg->high_vol_level = vol_suply[1];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* rtc6226_i2c_probe - probe for the device
|
||||
|
|
@ -507,6 +691,8 @@ static int rtc6226_i2c_probe(struct i2c_client *client,
|
|||
struct rtc6226_device *radio;
|
||||
struct v4l2_device *v4l2_dev;
|
||||
struct v4l2_ctrl_handler *hdl;
|
||||
struct regulator *vddvreg = NULL;
|
||||
struct regulator *viovreg = NULL;
|
||||
int retval = 0;
|
||||
int i = 0;
|
||||
int kfifo_alloc_rc = 0;
|
||||
|
|
@ -514,60 +700,113 @@ static int rtc6226_i2c_probe(struct i2c_client *client,
|
|||
/* struct v4l2_ctrl *ctrl; */
|
||||
/* need to add description "irq-fm" in dts */
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
FMDBG("%s enter\n", __func__);
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
retval = -ENODEV;
|
||||
goto err_initial;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* if voltage regulator is not ready yet, return the error
|
||||
* if error is -EPROBE_DEFER to kernel then probe will be called at
|
||||
* later point of time.
|
||||
*/
|
||||
viovreg = regulator_get(&client->dev, "vio");
|
||||
if (IS_ERR(viovreg)) {
|
||||
retval = PTR_ERR(viovreg);
|
||||
FMDERR("%s: regulator_get(vio) failed. retval=%d\n",
|
||||
__func__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
vddvreg = regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(vddvreg)) {
|
||||
retval = PTR_ERR(vddvreg);
|
||||
FMDERR("%s: regulator_get(vdd) failed. retval=%d\n",
|
||||
__func__, retval);
|
||||
regulator_put(viovreg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* private data allocation and initialization */
|
||||
radio = kzalloc(sizeof(struct rtc6226_device), GFP_KERNEL);
|
||||
if (!radio) {
|
||||
retval = -ENOMEM;
|
||||
goto err_initial;
|
||||
regulator_put(viovreg);
|
||||
regulator_put(vddvreg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
v4l2_dev = &radio->v4l2_dev;
|
||||
retval = v4l2_device_register(&client->dev, v4l2_dev);
|
||||
if (retval < 0) {
|
||||
pr_err("%s couldn't register v4l2_device\n", __func__);
|
||||
goto err_radio;
|
||||
FMDERR("%s couldn't register v4l2_device\n", __func__);
|
||||
goto err_vreg;
|
||||
}
|
||||
|
||||
pr_info("v4l2_device_register successfully\n");
|
||||
FMDBG("v4l2_device_register successfully\n");
|
||||
hdl = &radio->ctrl_handler;
|
||||
|
||||
radio->users = 0;
|
||||
/* initialize the device count */
|
||||
atomic_set(&radio->users, 0);
|
||||
radio->client = client;
|
||||
mutex_init(&radio->lock);
|
||||
init_completion(&radio->completion);
|
||||
|
||||
retval = rtc6226_parse_dt(&client->dev, radio);
|
||||
if (retval) {
|
||||
pr_err("%s: Parsing DT failed(%d)\n", __func__, retval);
|
||||
kfree(radio);
|
||||
return retval;
|
||||
FMDERR("%s: Parsing DT failed(%d)\n", __func__, retval);
|
||||
goto err_v4l2;
|
||||
}
|
||||
|
||||
radio->vddreg = devm_kzalloc(&client->dev,
|
||||
sizeof(struct fm_power_vreg_data),
|
||||
GFP_KERNEL);
|
||||
if (!radio->vddreg) {
|
||||
FMDERR("%s: allocating memory for vdd vreg failed\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_v4l2;
|
||||
}
|
||||
|
||||
radio->vddreg->reg = vddvreg;
|
||||
radio->vddreg->name = "vdd";
|
||||
radio->vddreg->is_enabled = false;
|
||||
retval = rtc6226_dt_parse_vreg_info(&client->dev,
|
||||
radio->vddreg, "rtc6226,vdd-supply-voltage");
|
||||
if (retval < 0) {
|
||||
FMDERR("%s: parsing vdd-supply failed\n", __func__);
|
||||
goto err_v4l2;
|
||||
}
|
||||
|
||||
radio->vioreg = devm_kzalloc(&client->dev,
|
||||
sizeof(struct fm_power_vreg_data),
|
||||
GFP_KERNEL);
|
||||
if (!radio->vioreg) {
|
||||
FMDERR("%s: allocating memory for vio vreg failed\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_v4l2;
|
||||
}
|
||||
radio->vioreg->reg = viovreg;
|
||||
radio->vioreg->name = "vio";
|
||||
radio->vioreg->is_enabled = false;
|
||||
retval = rtc6226_dt_parse_vreg_info(&client->dev,
|
||||
radio->vioreg, "rtc6226,vio-supply-voltage");
|
||||
if (retval < 0) {
|
||||
FMDERR("%s: parsing vio-supply failed\n", __func__);
|
||||
goto err_v4l2;
|
||||
}
|
||||
/* Initialize pin control*/
|
||||
retval = rtc6226_pinctrl_init(radio);
|
||||
if (retval) {
|
||||
pr_err("%s: rtc6226_pinctrl_init returned %d\n",
|
||||
FMDERR("%s: rtc6226_pinctrl_init returned %d\n",
|
||||
__func__, retval);
|
||||
/* if pinctrl is not supported, -EINVAL is returned*/
|
||||
if (retval == -EINVAL)
|
||||
retval = 0;
|
||||
} else {
|
||||
pr_info("%s rtc6226_pinctrl_init success\n", __func__);
|
||||
}
|
||||
|
||||
if (radio->ext_ldo_gpio > 0) {
|
||||
retval = gpio_direction_output(radio->ext_ldo_gpio, 1);
|
||||
if (retval) {
|
||||
pr_err("%s Unable to set direction(LDO)\n", __func__);
|
||||
kfree(radio);
|
||||
return retval;
|
||||
}
|
||||
FMDBG("%s rtc6226_pinctrl_init success\n", __func__);
|
||||
}
|
||||
|
||||
memcpy(&radio->videodev, &rtc6226_viddev_template,
|
||||
|
|
@ -582,7 +821,7 @@ static int rtc6226_i2c_probe(struct i2c_client *client,
|
|||
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
|
||||
if (!radio->buffer) {
|
||||
retval = -EIO;
|
||||
goto err_radio;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < RTC6226_FM_BUF_MAX; i++) {
|
||||
|
|
@ -592,15 +831,16 @@ static int rtc6226_i2c_probe(struct i2c_client *client,
|
|||
STD_BUF_SIZE, GFP_KERNEL);
|
||||
|
||||
if (kfifo_alloc_rc != 0) {
|
||||
pr_err("%s: failed allocating buffers %d\n",
|
||||
FMDERR("%s: failed allocating buffers %d\n",
|
||||
__func__, kfifo_alloc_rc);
|
||||
retval = -ENOMEM;
|
||||
goto err;
|
||||
goto err_rds;
|
||||
}
|
||||
}
|
||||
radio->wqueue = NULL;
|
||||
radio->wqueue_scan = NULL;
|
||||
radio->wqueue_rds = NULL;
|
||||
radio->band = -1;
|
||||
|
||||
/* rds buffer configuration */
|
||||
radio->wr_index = 0;
|
||||
|
|
@ -612,19 +852,19 @@ static int rtc6226_i2c_probe(struct i2c_client *client,
|
|||
radio->wqueue = create_singlethread_workqueue("fmradio");
|
||||
if (!radio->wqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto err_wqueue;
|
||||
goto err_rds;
|
||||
}
|
||||
|
||||
radio->wqueue_scan = create_singlethread_workqueue("fmradioscan");
|
||||
if (!radio->wqueue_scan) {
|
||||
retval = -ENOMEM;
|
||||
goto err_wqueue_scan;
|
||||
goto err_wqueue;
|
||||
}
|
||||
|
||||
radio->wqueue_rds = create_singlethread_workqueue("fmradiords");
|
||||
if (!radio->wqueue_rds) {
|
||||
retval = -ENOMEM;
|
||||
goto err_all;
|
||||
goto err_wqueue_scan;
|
||||
}
|
||||
|
||||
/* register video device */
|
||||
|
|
@ -632,27 +872,39 @@ static int rtc6226_i2c_probe(struct i2c_client *client,
|
|||
radio_nr);
|
||||
if (retval) {
|
||||
dev_info(&client->dev, "Could not register video device\n");
|
||||
goto err_rds;
|
||||
goto err_all;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, radio); /* move from below */
|
||||
pr_info("%s exit\n", __func__);
|
||||
FMDBG("%s exit\n", __func__);
|
||||
return 0;
|
||||
|
||||
err_all:
|
||||
destroy_workqueue(radio->wqueue_rds);
|
||||
err_wqueue_scan:
|
||||
destroy_workqueue(radio->wqueue_scan);
|
||||
err_rds:
|
||||
kfree(radio->buffer);
|
||||
err_wqueue:
|
||||
destroy_workqueue(radio->wqueue);
|
||||
err_rds:
|
||||
kfree(radio->buffer);
|
||||
err:
|
||||
video_device_release(&radio->videodev);
|
||||
err_v4l2:
|
||||
v4l2_device_unregister(v4l2_dev);
|
||||
err_radio:
|
||||
err_vreg:
|
||||
if (radio && radio->vioreg && radio->vioreg->reg) {
|
||||
regulator_put(radio->vioreg->reg);
|
||||
devm_kfree(&client->dev, radio->vioreg);
|
||||
} else {
|
||||
regulator_put(viovreg);
|
||||
}
|
||||
if (radio && radio->vddreg && radio->vddreg->reg) {
|
||||
regulator_put(radio->vddreg->reg);
|
||||
devm_kfree(&client->dev, radio->vddreg);
|
||||
} else {
|
||||
regulator_put(vddvreg);
|
||||
}
|
||||
kfree(radio);
|
||||
err_initial:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -670,7 +922,7 @@ static int rtc6226_i2c_remove(struct i2c_client *client)
|
|||
video_unregister_device(&radio->videodev);
|
||||
v4l2_device_unregister(&radio->v4l2_dev);
|
||||
kfree(radio);
|
||||
pr_info("%s exit\n", __func__);
|
||||
FMDBG("%s exit\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -684,7 +936,7 @@ static int rtc6226_i2c_suspend(struct device *dev)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct rtc6226_device *radio = i2c_get_clientdata(client);
|
||||
|
||||
pr_info("%s %d\n", __func__, radio->client->addr);
|
||||
FMDBG("%s %d\n", __func__, radio->client->addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -698,7 +950,7 @@ static int rtc6226_i2c_resume(struct device *dev)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct rtc6226_device *radio = i2c_get_clientdata(client);
|
||||
|
||||
pr_info("%s %d\n", __func__, radio->client->addr);
|
||||
FMDBG("%s %d\n", __func__, radio->client->addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -730,7 +982,7 @@ struct i2c_driver rtc6226_i2c_driver = {
|
|||
*/
|
||||
int rtc6226_i2c_init(void)
|
||||
{
|
||||
pr_info(DRIVER_DESC ", Version " DRIVER_VERSION "\n");
|
||||
FMDBG(DRIVER_DESC ", Version " DRIVER_VERSION "\n");
|
||||
return i2c_add_driver(&rtc6226_i2c_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,13 @@
|
|||
|
||||
#define RW_Kernel_ENG
|
||||
|
||||
#define DEBUG
|
||||
#undef FMDBG
|
||||
#define FMDBG(fmt, args...) pr_debug("rtc6226: " fmt, ##args)
|
||||
|
||||
#undef FMDERR
|
||||
#define FMDERR(fmt, args...) pr_err("rtc6226: " fmt, ##args)
|
||||
|
||||
/* driver definitions */
|
||||
#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1)
|
||||
#define DRIVER_CARD "Richwave rtc6226 FM Tuner"
|
||||
|
|
@ -182,7 +189,7 @@
|
|||
|
||||
#define WRAP_ENABLE 1
|
||||
#define WRAP_DISABLE 0
|
||||
|
||||
#define DEFAULT_RSSI_TH 8
|
||||
/* Standard buffer size */
|
||||
#define STD_BUF_SIZE 256
|
||||
|
||||
|
|
@ -191,6 +198,8 @@
|
|||
#define TUNE_PENDING 1
|
||||
#define SEEK_PENDING 2
|
||||
#define SCAN_PENDING 3
|
||||
#define START_SCAN 1
|
||||
#define WAIT_TIMEOUT_MSEC 7000
|
||||
|
||||
#define RTC6226_MIN_SRCH_MODE 0x00
|
||||
#define RTC6226_MAX_SRCH_MODE 0x02
|
||||
|
|
@ -302,6 +311,8 @@
|
|||
#define GET_AF_LIST_LEN(x) (x*4)
|
||||
#define MIN_AF_FREQ_CODE 1
|
||||
#define MAX_AF_FREQ_CODE 204
|
||||
#define MIN_RSSI 0
|
||||
#define MAX_RSSI 15
|
||||
|
||||
/* 25 AFs supported for a freq. 224 means 1 AF. 225 means 2 AFs and so on */
|
||||
#define NO_AF_CNT_CODE 224
|
||||
|
|
@ -314,6 +325,8 @@
|
|||
#define CH_SPACING_200 200
|
||||
#define CH_SPACING_100 100
|
||||
#define CH_SPACING_50 50
|
||||
#define TURNING_ON 1
|
||||
#define TURNING_OFF 0
|
||||
|
||||
#define RW_PRIBASE (V4L2_CID_USER_BASE | 0xf000)
|
||||
|
||||
|
|
@ -349,12 +362,11 @@
|
|||
#define V4L2_CID_PRIVATE_RDS_SYNC (RW_PRIBASE + (CHIPID<<4) + 5)
|
||||
#define V4L2_CID_PRIVATE_SI (RW_PRIBASE + (CHIPID<<4) + 6)
|
||||
|
||||
#define WAIT_OVER 0
|
||||
#define SEEK_WAITING 1
|
||||
#define NO_WAIT 2
|
||||
#define TUNE_WAITING 4
|
||||
#define RDS_WAITING 5
|
||||
#define SEEK_CANCEL 6
|
||||
#define TUNE_PARAM 16
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Definitions
|
||||
**************************************************************************/
|
||||
|
|
@ -438,6 +450,18 @@ struct rtc6226_af_info {
|
|||
u32 af_list[MAX_NO_OF_AF];
|
||||
};
|
||||
|
||||
struct fm_power_vreg_data {
|
||||
/* voltage regulator handle */
|
||||
struct regulator *reg;
|
||||
/* regulator name */
|
||||
const char *name;
|
||||
/* voltage levels to be set */
|
||||
unsigned int low_vol_level;
|
||||
unsigned int high_vol_level;
|
||||
/* is this regulator enabled? */
|
||||
bool is_enabled;
|
||||
};
|
||||
|
||||
/*
|
||||
* rtc6226_device - private data
|
||||
*/
|
||||
|
|
@ -453,9 +477,11 @@ struct rtc6226_device {
|
|||
struct pinctrl_state *gpio_state_active;
|
||||
struct pinctrl_state *gpio_state_suspend;
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
struct fm_power_vreg_data *vddreg;
|
||||
struct fm_power_vreg_data *vioreg;
|
||||
int band;
|
||||
int space;
|
||||
unsigned int users;
|
||||
atomic_t users;
|
||||
unsigned int mode;
|
||||
u8 seek_tune_status;
|
||||
u8 rssi_th;
|
||||
|
|
@ -666,3 +692,5 @@ void rtc6226_scan(struct work_struct *work);
|
|||
void rtc6226_search(struct rtc6226_device *radio, bool on);
|
||||
int rtc6226_cancel_seek(struct rtc6226_device *radio);
|
||||
void rtc6226_rds_handler(struct work_struct *worker);
|
||||
void rtc6226_q_event(struct rtc6226_device *radio, enum rtc6226_evt_t event);
|
||||
int rtc6226_reset_rds_data(struct rtc6226_device *radio);
|
||||
|
|
|
|||
Loading…
Reference in a new issue