adv7481: Fix issues with adv7481 driver functionality
Fix memory allocation and probing crashes in adv7481 driver. Add support for DT and GPIO configurations. CRs-Fixed: 998927 Change-Id: I056dbecbd2b3c7c2c0bc0314b9c68e992452d84f Signed-off-by: Shiju Mathew <shijum@codeaurora.org>
This commit is contained in:
parent
10ce2a7380
commit
11f3d4d0e8
2 changed files with 46 additions and 102 deletions
|
@ -10,6 +10,9 @@ Required properties
|
|||
- compatible: "qcom,adv7481"
|
||||
- qcom,slave-addr: The i2c slave address of adv7481 driver.
|
||||
- qcom,cci-master: The i2c master id to be used for adv7481 driver.
|
||||
- gpios: The GPIOs required to be configured for the driver. It should
|
||||
be in the order I2C data line, i2c clock line, reset line,
|
||||
interrupt 1, interrupt 2 and interrupt 3.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -17,4 +20,10 @@ Example:
|
|||
compatible = "qcom,adv7481";
|
||||
qcom,cci-master = <0>;
|
||||
qcom,slave-addr = <0x70>;
|
||||
gpios = <&tlmm 17 0>, /* I2C SDA */
|
||||
<&tlmm 18 0>, /* I2C SCL */
|
||||
<&pm8994_gpios 4 0>, /* RST */
|
||||
<&pm8994_gpios 5 0>, /* INT1 */
|
||||
<&pm8994_gpios 6 0>, /* INT2 */
|
||||
<&pm8994_gpios 7 0>; /* INT3 */
|
||||
};
|
||||
|
|
|
@ -77,22 +77,12 @@ enum adv7481_gpio_t {
|
|||
};
|
||||
|
||||
struct adv7481_state {
|
||||
/* Platform Data */
|
||||
struct adv7481_platform_data pdata;
|
||||
struct device *dev;
|
||||
|
||||
/* VREG */
|
||||
struct camera_vreg_t *cci_vreg;
|
||||
struct regulator *cci_reg_ptr[MAX_REGULATOR];
|
||||
int32_t regulator_count;
|
||||
|
||||
/* I2C */
|
||||
struct msm_camera_i2c_client i2c_client;
|
||||
u32 cci_master;
|
||||
u32 i2c_slave_addr;
|
||||
u32 i2c_csi_slave_addr;
|
||||
u32 i2c_vpp_slave_addr;
|
||||
u32 register_page;
|
||||
|
||||
/* V4L2 Data */
|
||||
struct v4l2_subdev sd;
|
||||
|
@ -590,7 +580,7 @@ static int adv7481_dev_init(struct adv7481_state *state)
|
|||
ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
|
||||
IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
|
||||
/* Delay required following I2C reset and I2C transactions */
|
||||
usleep_range(I2C_SW_RST_DELAY, I2C_SW_RST_DELAY + 1000);
|
||||
udelay(I2C_SW_RST_DELAY);
|
||||
|
||||
chip_rev_id = adv7481_rd_word(&state->i2c_client, state->i2c_io_addr,
|
||||
IO_REG_CHIP_REV_ID_1_ADDR);
|
||||
|
@ -679,12 +669,10 @@ static int adv7481_hw_init(struct adv7481_state *state)
|
|||
if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_RST].gpio)) {
|
||||
ret |= gpio_direction_output(
|
||||
state->gpio_array[ADV7481_GPIO_RST].gpio, 0);
|
||||
usleep_range(GPIO_HW_RST_DELAY_LOW, GPIO_HW_RST_DELAY_LOW +
|
||||
1000);
|
||||
udelay(GPIO_HW_RST_DELAY_LOW);
|
||||
ret |= gpio_direction_output(
|
||||
state->gpio_array[ADV7481_GPIO_RST].gpio, 1);
|
||||
usleep_range(GPIO_HW_RST_DELAY_HI, GPIO_HW_RST_DELAY_HI +
|
||||
1000);
|
||||
udelay(GPIO_HW_RST_DELAY_HI);
|
||||
if (ret) {
|
||||
pr_err("%s: Set GPIO Fail %d\n", __func__, ret);
|
||||
goto err_exit;
|
||||
|
@ -2037,6 +2025,10 @@ static int adv7481_cci_init(struct adv7481_state *state)
|
|||
}
|
||||
cci_client->cci_subdev = msm_cci_get_subdev();
|
||||
pr_debug("%s cci_subdev: %p\n", __func__, cci_client->cci_subdev);
|
||||
if (!cci_client->cci_subdev) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_cci_init;
|
||||
}
|
||||
cci_client->cci_i2c_master = state->cci_master;
|
||||
cci_client->sid = state->i2c_slave_addr;
|
||||
cci_client->retries = 3;
|
||||
|
@ -2057,77 +2049,47 @@ err_cci_init:
|
|||
static int adv7481_parse_dt(struct adv7481_state *state)
|
||||
{
|
||||
struct device_node *np = state->dev->of_node;
|
||||
unsigned int i;
|
||||
uint32_t i = 0;
|
||||
int gpio_count = 0;
|
||||
int flag_count = 0;
|
||||
int label_count = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* config CCI */
|
||||
ret = of_property_read_u32(np, "qcom,cci-master",
|
||||
&state->cci_master);
|
||||
if (ret < 0 || state->cci_master >= MASTER_MAX) {
|
||||
pr_err("%s: failed ret %d\n", __func__, ret);
|
||||
pr_err("%s: failed to read cci master . ret %d\n",
|
||||
__func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: cci_master: 0x%x\n", __func__, state->cci_master);
|
||||
ret = of_property_read_u32(np, "qcom,slave-addr",
|
||||
&state->i2c_slave_addr);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed ret %d\n", __func__, ret);
|
||||
pr_err("%s: failed to read slave-addr. ret %d\n",
|
||||
__func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: i2c_slave_addr: 0x%x\n", __func__, state->i2c_slave_addr);
|
||||
state->i2c_io_addr = (uint8_t)state->i2c_slave_addr;
|
||||
|
||||
ret = of_property_read_u32(np, "qcom,csi-slave-addr",
|
||||
&state->i2c_csi_slave_addr);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed ret %d\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: i2c_csi_slave_addr: 0x%x\n", __func__,
|
||||
state->i2c_csi_slave_addr);
|
||||
ret = of_property_read_u32(np, "qcom,vpp-slave-addr",
|
||||
&state->i2c_vpp_slave_addr);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed ret %d\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: i2c_vpp_slave_addr: 0x%x\n", __func__,
|
||||
state->i2c_vpp_slave_addr);
|
||||
|
||||
ret = adv7481_cci_init(state);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed adv7481_cci_init ret %d\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
/* Configure GPIOs */
|
||||
gpio_count = of_gpio_count(np);
|
||||
pr_debug("%s: of_gpio_count: 0x%x\n", __func__, gpio_count);
|
||||
flag_count = of_property_count_u32_elems(np, "qcom,gpio-tbl-flags");
|
||||
pr_debug("%s: gpio-tbl-flags: 0x%x\n", __func__, flag_count);
|
||||
label_count = of_property_count_strings(np, "qcom,gpio-tbl-label");
|
||||
pr_debug("%s: gpio-tbl-label: 0x%x\n", __func__, label_count);
|
||||
if (gpio_count != ADV7481_GPIO_MAX ||
|
||||
flag_count != ADV7481_GPIO_MAX ||
|
||||
label_count != ADV7481_GPIO_MAX) {
|
||||
if (gpio_count != ADV7481_GPIO_MAX) {
|
||||
ret = -EFAULT;
|
||||
pr_err("%s: failed to configure GPIO ret -EFAULT\n", __func__);
|
||||
pr_err("%s: dt gpio count %d doesn't match required. ret %d\n",
|
||||
__func__, gpio_count, ret);
|
||||
goto exit;
|
||||
}
|
||||
for (i = 0; i < ADV7481_GPIO_MAX; i++) {
|
||||
u32 tmp;
|
||||
|
||||
state->gpio_array[i].gpio = of_get_gpio(np, i);
|
||||
of_property_read_u32_index(np, "qcom,gpio-tbl-flags", i, &tmp);
|
||||
state->gpio_array[i].flags = tmp;
|
||||
of_property_read_string_index(np, "qcom,gpio-tbl-label", i,
|
||||
&state->gpio_array[i].label);
|
||||
pr_debug("%s: gpio_array[%d] = %d\n", __func__, i,
|
||||
state->gpio_array[i].gpio);
|
||||
state->gpio_array[i].gpio = of_get_gpio_flags(np, i,
|
||||
(enum of_gpio_flags *)&state->gpio_array[i].flags);
|
||||
if (!gpio_is_valid(state->gpio_array[i].gpio)) {
|
||||
pr_err("invalid gpio setting for index %d\n", i);
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: gpio_array[%d] = %d flag = %ld\n", __func__, i,
|
||||
state->gpio_array[i].gpio, state->gpio_array[i].flags);
|
||||
}
|
||||
pr_debug("%s: End read back gpio from dt...", __func__);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
|
@ -2143,7 +2105,6 @@ static int adv7481_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct adv7481_state *state;
|
||||
const struct of_device_id *device_id;
|
||||
struct adv7481_platform_data *pdata = NULL;
|
||||
struct v4l2_subdev *sd;
|
||||
int ret;
|
||||
|
||||
|
@ -2161,44 +2122,19 @@ static int adv7481_probe(struct platform_device *pdev)
|
|||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
platform_set_drvdata(pdev, state);
|
||||
state->dev = &pdev->dev;
|
||||
|
||||
mutex_init(&state->mutex);
|
||||
|
||||
/* config VREG */
|
||||
ret = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
|
||||
&(state->cci_vreg), &(state->regulator_count));
|
||||
if (ret < 0) {
|
||||
pr_err("%s:cci get_dt_vreg failed\n", __func__);
|
||||
goto err_mem_free;
|
||||
}
|
||||
|
||||
ret = msm_camera_config_vreg(&pdev->dev, state->cci_vreg,
|
||||
state->regulator_count, NULL, 0,
|
||||
&state->cci_reg_ptr[0], 1);
|
||||
if (ret < 0) {
|
||||
pr_err("%s:cci config_vreg failed\n", __func__);
|
||||
goto err_mem_free;
|
||||
}
|
||||
|
||||
ret = msm_camera_enable_vreg(&pdev->dev, state->cci_vreg,
|
||||
state->regulator_count, NULL, 0,
|
||||
&state->cci_reg_ptr[0], 1);
|
||||
if (ret < 0) {
|
||||
pr_err("%s:cci enable_vreg failed\n", __func__);
|
||||
goto err_mem_free;
|
||||
}
|
||||
pr_debug("%s - VREG Initialized...\n", __func__);
|
||||
|
||||
ret = adv7481_parse_dt(state);
|
||||
pr_debug("%s - Done parsing dt...\n", __func__);
|
||||
if (ret < 0) {
|
||||
pr_err("Error parsing dt tree\n");
|
||||
goto err_mem_free;
|
||||
}
|
||||
|
||||
/* Get and Check Platform Data */
|
||||
pdata = (struct adv7481_platform_data *) pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
ret = -ENOMEM;
|
||||
pr_err("%s(%d): Getting Platform data failed\n",
|
||||
__func__, __LINE__);
|
||||
ret = adv7481_cci_init(state);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed adv7481_cci_init ret %d\n", __func__, ret);
|
||||
goto err_mem_free;
|
||||
}
|
||||
|
||||
|
@ -2265,19 +2201,18 @@ static int adv7481_probe(struct platform_device *pdev)
|
|||
|
||||
err_media_entity:
|
||||
media_entity_cleanup(&sd->entity);
|
||||
|
||||
err_mem_free:
|
||||
kfree(state);
|
||||
devm_kfree(&pdev->dev, state);
|
||||
|
||||
err:
|
||||
if (!ret)
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7481_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct adv7481_state *state;
|
||||
struct adv7481_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
state = pdev->dev.platform_data;
|
||||
msm_ba_unregister_subdev_node(&state->sd);
|
||||
v4l2_device_unregister_subdev(&state->sd);
|
||||
media_entity_cleanup(&state->sd.entity);
|
||||
|
@ -2290,7 +2225,7 @@ static int adv7481_remove(struct platform_device *pdev)
|
|||
|
||||
cancel_delayed_work(&state->irq_delayed_work);
|
||||
mutex_destroy(&state->mutex);
|
||||
kfree(state);
|
||||
devm_kfree(&pdev->dev, state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue