Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49545638 authored by Shiju Mathew's avatar Shiju Mathew
Browse files

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: default avatarShiju Mathew <shijum@codeaurora.org>
parent 410e920b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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    */
	};
+34 −99
Original line number Diff line number Diff line
@@ -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;
@@ -589,7 +579,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);
@@ -678,12 +668,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;
@@ -2036,6 +2024,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;
@@ -2056,77 +2048,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;
@@ -2142,7 +2104,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;

@@ -2160,44 +2121,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);
	ret = adv7481_parse_dt(state);
	if (ret < 0) {
		pr_err("%s:cci config_vreg failed\n", __func__);
		pr_err("Error parsing dt tree\n");
		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);
	ret = adv7481_cci_init(state);
	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__);

	/* 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__);
		pr_err("%s: failed adv7481_cci_init ret %d\n", __func__, ret);
		goto err_mem_free;
	}

@@ -2264,19 +2200,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);
@@ -2289,7 +2224,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;
}