Loading drivers/media/radio/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -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. Loading drivers/media/radio/rtc6226/radio-rtc6226-common.c +2 −0 Original line number Diff line number Diff line Loading @@ -1686,6 +1686,8 @@ int rtc6226_vidioc_g_ctrl(struct file *file, void *priv, case V4L2_CID_PRIVATE_RTC6226_RDSGROUP_PROC: break; case V4L2_CID_PRIVATE_RTC6226_SIGNAL_TH: /* intentional fallthrough */ case V4L2_CID_PRIVATE_RTC6226_RSSI_TH: ctrl->value = radio->rssi_th; break; default: Loading drivers/media/radio/rtc6226/radio-rtc6226-i2c.c +256 −25 Original line number Diff line number Diff line Loading @@ -390,6 +390,133 @@ int rtc6226_enable_irq(struct rtc6226_device *radio) 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) { pr_err("In %s, vio reg is NULL\n", __func__); return rc; } if (on) { pr_debug("vreg is : %s\n", vreg->name); rc = regulator_set_voltage(vreg->reg, vreg->low_vol_level, vreg->high_vol_level); if (rc < 0) { pr_err("set_vol(%s) fail %d\n", vreg->name, rc); return rc; } rc = regulator_enable(vreg->reg); if (rc < 0) { pr_err("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) { pr_err("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) { pr_err("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) { pr_err("In %s, vdd reg is NULL\n", __func__); return rc; } if (on) { pr_debug("vreg is : %s\n", vreg->name); rc = regulator_set_voltage(vreg->reg, vreg->low_vol_level, vreg->high_vol_level); if (rc < 0) { pr_err("set_vol(%s) fail %d\n", vreg->name, rc); return rc; } rc = regulator_enable(vreg->reg); if (rc < 0) { pr_err("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) { pr_err("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) { pr_err("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) { pr_err("In %s, vdd reg cfg failed %x\n", __func__, rc); return rc; } rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); if (rc < 0) { pr_err("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) pr_err("In %s, vdd reg cfg failed %x\n", __func__, rc); rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); if (rc < 0) pr_err("In %s, vio reg cfg failed %x\n", __func__, rc); } return rc; } /* * rtc6226_fops_open - file open */ Loading @@ -415,13 +542,30 @@ int rtc6226_fops_open(struct file *file) INIT_DELAYED_WORK(&radio->work_scan, rtc6226_scan); INIT_WORK(&radio->rds_worker, rtc6226_rds_handler); /* Power up Supply voltage to VDD and VIO */ retval = rtc6226_fm_power_cfg(radio, TURNING_ON); if (retval) { pr_err("%s: failed to supply voltage\n", __func__); goto open_err_setup; } retval = rtc6226_enable_irq(radio); /* Wait for the value to take effect on gpio. */ msleep(100); rtc6226_enable_irq(radio); if (retval) { pr_err("%s:enable irq failed\n", __func__); goto open_err_req_irq; } if (retval) v4l2_fh_release(file); return retval; open_err_req_irq: rtc6226_fm_power_cfg(radio, TURNING_OFF); open_err_setup: radio->users--; return retval; } /* Loading @@ -430,6 +574,7 @@ int rtc6226_fops_open(struct file *file) int rtc6226_fops_release(struct file *file) { struct rtc6226_device *radio = video_drvdata(file); int retval = 0; pr_info("%s : Exit\n", __func__); if (v4l2_fh_is_singular_file(file)) { Loading @@ -440,6 +585,9 @@ int rtc6226_fops_release(struct file *file) } rtc6226_disable_irq(radio); radio->users--; retval = rtc6226_fm_power_cfg(radio, TURNING_OFF); if (retval < 0) pr_err("%s: failed to apply voltage\n", __func__); return v4l2_fh_release(file); } Loading Loading @@ -520,6 +668,23 @@ static int rtc6226_pinctrl_init(struct rtc6226_device *radio) 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) { pr_err("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 Loading @@ -530,6 +695,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; Loading @@ -540,21 +707,45 @@ static int rtc6226_i2c_probe(struct i2c_client *client, pr_info("%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); pr_err("%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); pr_err("%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; goto err_vreg; } pr_info("v4l2_device_register successfully\n"); Loading @@ -568,10 +759,47 @@ static int rtc6226_i2c_probe(struct i2c_client *client, retval = rtc6226_parse_dt(&client->dev, radio); if (retval) { pr_err("%s: Parsing DT failed(%d)\n", __func__, retval); kfree(radio); return retval; goto err_v4l2; } radio->vddreg = devm_kzalloc(&client->dev, sizeof(struct fm_power_vreg_data), GFP_KERNEL); if (!radio->vddreg) { pr_err("%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) { pr_err("%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) { pr_err("%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) { pr_err("%s: parsing vio-supply failed\n", __func__); goto err_v4l2; } /* Initialize pin control*/ retval = rtc6226_pinctrl_init(radio); if (retval) { Loading @@ -584,15 +812,6 @@ static int rtc6226_i2c_probe(struct i2c_client *client, 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; } } memcpy(&radio->videodev, &rtc6226_viddev_template, sizeof(struct video_device)); Loading @@ -605,7 +824,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++) { Loading @@ -618,7 +837,7 @@ static int rtc6226_i2c_probe(struct i2c_client *client, pr_err("%s: failed allocating buffers %d\n", __func__, kfifo_alloc_rc); retval = -ENOMEM; goto err; goto err_rds; } } radio->wqueue = NULL; Loading @@ -636,19 +855,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 */ Loading @@ -656,7 +875,7 @@ 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 */ Loading @@ -667,16 +886,28 @@ static int rtc6226_i2c_probe(struct i2c_client *client, 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; } Loading drivers/media/radio/rtc6226/radio-rtc6226.h +16 −0 Original line number Diff line number Diff line Loading @@ -318,6 +318,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) Loading Loading @@ -441,6 +443,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 */ Loading @@ -456,6 +470,8 @@ 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; Loading drivers/media/v4l2-core/v4l2-dev.c +3 −0 Original line number Diff line number Diff line Loading @@ -716,6 +716,9 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid); } else { /* ioctls valid for radio */ SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf); } if (is_tx && (is_radio || is_sdr)) { /* radio transmitter only ioctls */ Loading Loading
drivers/media/radio/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -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. Loading
drivers/media/radio/rtc6226/radio-rtc6226-common.c +2 −0 Original line number Diff line number Diff line Loading @@ -1686,6 +1686,8 @@ int rtc6226_vidioc_g_ctrl(struct file *file, void *priv, case V4L2_CID_PRIVATE_RTC6226_RDSGROUP_PROC: break; case V4L2_CID_PRIVATE_RTC6226_SIGNAL_TH: /* intentional fallthrough */ case V4L2_CID_PRIVATE_RTC6226_RSSI_TH: ctrl->value = radio->rssi_th; break; default: Loading
drivers/media/radio/rtc6226/radio-rtc6226-i2c.c +256 −25 Original line number Diff line number Diff line Loading @@ -390,6 +390,133 @@ int rtc6226_enable_irq(struct rtc6226_device *radio) 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) { pr_err("In %s, vio reg is NULL\n", __func__); return rc; } if (on) { pr_debug("vreg is : %s\n", vreg->name); rc = regulator_set_voltage(vreg->reg, vreg->low_vol_level, vreg->high_vol_level); if (rc < 0) { pr_err("set_vol(%s) fail %d\n", vreg->name, rc); return rc; } rc = regulator_enable(vreg->reg); if (rc < 0) { pr_err("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) { pr_err("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) { pr_err("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) { pr_err("In %s, vdd reg is NULL\n", __func__); return rc; } if (on) { pr_debug("vreg is : %s\n", vreg->name); rc = regulator_set_voltage(vreg->reg, vreg->low_vol_level, vreg->high_vol_level); if (rc < 0) { pr_err("set_vol(%s) fail %d\n", vreg->name, rc); return rc; } rc = regulator_enable(vreg->reg); if (rc < 0) { pr_err("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) { pr_err("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) { pr_err("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) { pr_err("In %s, vdd reg cfg failed %x\n", __func__, rc); return rc; } rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); if (rc < 0) { pr_err("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) pr_err("In %s, vdd reg cfg failed %x\n", __func__, rc); rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); if (rc < 0) pr_err("In %s, vio reg cfg failed %x\n", __func__, rc); } return rc; } /* * rtc6226_fops_open - file open */ Loading @@ -415,13 +542,30 @@ int rtc6226_fops_open(struct file *file) INIT_DELAYED_WORK(&radio->work_scan, rtc6226_scan); INIT_WORK(&radio->rds_worker, rtc6226_rds_handler); /* Power up Supply voltage to VDD and VIO */ retval = rtc6226_fm_power_cfg(radio, TURNING_ON); if (retval) { pr_err("%s: failed to supply voltage\n", __func__); goto open_err_setup; } retval = rtc6226_enable_irq(radio); /* Wait for the value to take effect on gpio. */ msleep(100); rtc6226_enable_irq(radio); if (retval) { pr_err("%s:enable irq failed\n", __func__); goto open_err_req_irq; } if (retval) v4l2_fh_release(file); return retval; open_err_req_irq: rtc6226_fm_power_cfg(radio, TURNING_OFF); open_err_setup: radio->users--; return retval; } /* Loading @@ -430,6 +574,7 @@ int rtc6226_fops_open(struct file *file) int rtc6226_fops_release(struct file *file) { struct rtc6226_device *radio = video_drvdata(file); int retval = 0; pr_info("%s : Exit\n", __func__); if (v4l2_fh_is_singular_file(file)) { Loading @@ -440,6 +585,9 @@ int rtc6226_fops_release(struct file *file) } rtc6226_disable_irq(radio); radio->users--; retval = rtc6226_fm_power_cfg(radio, TURNING_OFF); if (retval < 0) pr_err("%s: failed to apply voltage\n", __func__); return v4l2_fh_release(file); } Loading Loading @@ -520,6 +668,23 @@ static int rtc6226_pinctrl_init(struct rtc6226_device *radio) 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) { pr_err("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 Loading @@ -530,6 +695,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; Loading @@ -540,21 +707,45 @@ static int rtc6226_i2c_probe(struct i2c_client *client, pr_info("%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); pr_err("%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); pr_err("%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; goto err_vreg; } pr_info("v4l2_device_register successfully\n"); Loading @@ -568,10 +759,47 @@ static int rtc6226_i2c_probe(struct i2c_client *client, retval = rtc6226_parse_dt(&client->dev, radio); if (retval) { pr_err("%s: Parsing DT failed(%d)\n", __func__, retval); kfree(radio); return retval; goto err_v4l2; } radio->vddreg = devm_kzalloc(&client->dev, sizeof(struct fm_power_vreg_data), GFP_KERNEL); if (!radio->vddreg) { pr_err("%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) { pr_err("%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) { pr_err("%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) { pr_err("%s: parsing vio-supply failed\n", __func__); goto err_v4l2; } /* Initialize pin control*/ retval = rtc6226_pinctrl_init(radio); if (retval) { Loading @@ -584,15 +812,6 @@ static int rtc6226_i2c_probe(struct i2c_client *client, 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; } } memcpy(&radio->videodev, &rtc6226_viddev_template, sizeof(struct video_device)); Loading @@ -605,7 +824,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++) { Loading @@ -618,7 +837,7 @@ static int rtc6226_i2c_probe(struct i2c_client *client, pr_err("%s: failed allocating buffers %d\n", __func__, kfifo_alloc_rc); retval = -ENOMEM; goto err; goto err_rds; } } radio->wqueue = NULL; Loading @@ -636,19 +855,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 */ Loading @@ -656,7 +875,7 @@ 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 */ Loading @@ -667,16 +886,28 @@ static int rtc6226_i2c_probe(struct i2c_client *client, 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; } Loading
drivers/media/radio/rtc6226/radio-rtc6226.h +16 −0 Original line number Diff line number Diff line Loading @@ -318,6 +318,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) Loading Loading @@ -441,6 +443,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 */ Loading @@ -456,6 +470,8 @@ 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; Loading
drivers/media/v4l2-core/v4l2-dev.c +3 −0 Original line number Diff line number Diff line Loading @@ -716,6 +716,9 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid); } else { /* ioctls valid for radio */ SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf); } if (is_tx && (is_radio || is_sdr)) { /* radio transmitter only ioctls */ Loading