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

Commit 75008673 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "leds: leds-qpnp-flash: add PON regulator support"

parents f8d443a4 3939b483
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -90,13 +90,18 @@ operational simplification. For backward compatibility purpose, switch node can
Optional properties inside child node:
- qcom,current		: default current intensity for LED. Accepted values should be
			  integer from 0 t 1000 inclusive, indicating 0 to 1000 mA.
- boost-supply		: flash LED boost power source for flash LED
- boost-voltage-max	: maximum voltage for flash LED boost regulator in uV. This attribute is
			required if boost-supply is defined.
- qcom,duration	: Duration for flash LED. When duration time expires, hardware will turn off
		flash LED. Values should be from 10 ms to 1280 ms with 10 ms incremental
		step. Not applicable to torch. It is required for LED:SWITCH node to handle
		LED used as flash.
- reg<n>	: reg<n> (<n> represents number. eg 0,1,2,..) property is to add support for
		multiple power sources. It includes two properties regulator-name and max-voltage.
		Required property inside regulator node:
		- regulator-name	: This denotes this node is a regulator node and which
					regulator to use.
		Optional property inside regulator node:
		- max-voltage		: This specifies max voltage of regulator. Some switch
					or boost regulator does not need this property.

Example:
	qcom,leds@d300 {
@@ -145,7 +150,12 @@ Example:
			qcom,max-current = <200>;
			qcom,id = <0>;
			qcom,current = <120>;
			boost-voltage-max = <3600000>;
			qcom,max-current = <200>;
			reg0 {
				regulator-name =
					 "pm8226_chg_boost";
				max-voltage = <3600000>;
			};
		};

		pm8226_switch: qcom,switch {
@@ -157,8 +167,11 @@ Example:
			qcom,current = <625>;
			qcom,duration = <1280>;
			qcom,max-current = <1000>;
			boost-supply = <pm8226_chg_boost>;
			boost-voltage-max = <3600000>;
			reg0 {
				regulator-name =
					"pm8226_chg_boost";
				max-voltage = <3600000>;
			};
		};
	};
+178 −78
Original line number Diff line number Diff line
@@ -163,16 +163,20 @@ enum current_ramp_steps {
	RAMP_STEP_27US,
};

struct flash_regulator_data {
	struct regulator	*regs;
	const char		*reg_name;
	u32			max_volt_uv;
};

/*
 * Configurations for each individual LED
 */
struct flash_node_data {
	struct spmi_device		*spmi_dev;
	struct led_classdev		cdev;
	struct regulator		*boost_regulator;
	struct work_struct		work;
	struct delayed_work		dwork;
	u32				boost_voltage_max;
	struct flash_regulator_data	*reg_data;
	u16				max_current;
	u16				prgm_current;
	u16				prgm_current2;
@@ -181,6 +185,7 @@ struct flash_node_data {
	u8				type;
	u8				trigger;
	u8				enable;
	u8				num_regulators;
	bool				flash_on;
};

@@ -1002,6 +1007,131 @@ led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
	return led_cdev->brightness;
}

static int flash_regulator_parse_dt(struct qpnp_flash_led *led,
					struct flash_node_data *flash_node) {

	int i = 0, rc;
	struct device_node *node = flash_node->cdev.dev->of_node;
	struct device_node *temp = NULL;
	const char *temp_string;
	u32 val;

	flash_node->reg_data = devm_kzalloc(&led->spmi_dev->dev,
					sizeof(struct flash_regulator_data *) *
						flash_node->num_regulators,
						GFP_KERNEL);
	if (!flash_node->reg_data) {
		dev_err(&led->spmi_dev->dev,
				"Unable to allocate memory\n");
		return -ENOMEM;
	}

	for_each_child_of_node(node, temp) {
		rc = of_property_read_string(temp, "regulator-name",
							&temp_string);
		if (!rc)
			flash_node->reg_data[i].reg_name = temp_string;
		else {
			dev_err(&led->spmi_dev->dev,
					"Unable to read regulator name\n");
			return rc;
		}

		if (of_find_property(temp, "max-voltage", NULL)) {
			rc = of_property_read_u32(temp, "max-voltage", &val);
			if (!rc) {
				flash_node->reg_data[i].max_volt_uv = val;
			} else {
				dev_err(&led->spmi_dev->dev,
						"Unable to read max voltage\n");
				return rc;
			}
		}
		i++;
	}

	return rc;
}

static int flash_regulator_setup(struct qpnp_flash_led *led,
				struct flash_node_data *flash_node, bool on)
{
	int i, rc = 0;

	if (on == false) {
		i = flash_node->num_regulators;
		goto error_regulator_setup;
	}

	for (i = 0; i < flash_node->num_regulators; i++) {
		flash_node->reg_data[i].regs =
			regulator_get(flash_node->cdev.dev,
					flash_node->reg_data[i].reg_name);
		if (IS_ERR(flash_node->reg_data[i].regs)) {
			rc = PTR_ERR(flash_node->reg_data[i].regs);
			dev_err(&led->spmi_dev->dev,
					"Failed to get regulator\n");
			goto error_regulator_setup;
		}

		if (regulator_count_voltages(flash_node->reg_data[i].regs)
									> 0) {
			rc = regulator_set_voltage(flash_node->reg_data[i].regs,
					flash_node->reg_data[i].max_volt_uv,
					flash_node->reg_data[i].max_volt_uv);
			if (rc) {
				dev_err(&led->spmi_dev->dev,
					"regulator set voltage failed\n");
				regulator_put(flash_node->reg_data[i].regs);
				goto error_regulator_setup;
			}
		}
	}

	return rc;

error_regulator_setup:
	while (i--) {
		if (regulator_count_voltages(flash_node->reg_data[i].regs)
									> 0) {
			regulator_set_voltage(flash_node->reg_data[i].regs,
				0, flash_node->reg_data[i].max_volt_uv);
		}

		regulator_put(flash_node->reg_data[i].regs);
	}

	return rc;
}

static int flash_regulator_enable(struct qpnp_flash_led *led,
				struct flash_node_data *flash_node, bool on)
{
	int i, rc = 0;

	if (on == false) {
		i = flash_node->num_regulators;
		goto error_regulator_enable;
	}

	for (i = 0; i < flash_node->num_regulators; i++) {
		rc = regulator_enable(flash_node->reg_data[i].regs);
		if (rc) {
			dev_err(&led->spmi_dev->dev,
					"regulator enable failed\n");
			goto error_regulator_enable;
		}
	}

	return rc;

error_regulator_enable:
	while (i--)
		regulator_disable(flash_node->reg_data[i].regs);

	return rc;
}

static void qpnp_flash_led_work(struct work_struct *work)
{
	struct flash_node_data *flash_node = container_of(work,
@@ -1020,27 +1150,14 @@ static void qpnp_flash_led_work(struct work_struct *work)
	if (!brightness)
		goto turn_off;

	if (flash_node->boost_regulator && !flash_node->flash_on) {
		if (regulator_count_voltages(flash_node->boost_regulator) > 0) {
			rc = regulator_set_voltage(flash_node->boost_regulator,
					flash_node->boost_voltage_max,
					flash_node->boost_voltage_max);
	if (!flash_node->flash_on && flash_node->num_regulators > 0) {
		rc = flash_regulator_enable(led, flash_node, true);
		if (rc) {
				dev_err(&led->spmi_dev->dev,
					"boost regulator set voltage failed\n");
			mutex_unlock(&led->flash_led_lock);
			return;
		}
	}

		rc = regulator_enable(flash_node->boost_regulator);
		if (rc) {
			dev_err(&led->spmi_dev->dev,
				"Boost regulator enablement failed\n");
			goto error_regulator_enable;
		}
	}

	if (!led->gpio_enabled && led->pinctrl) {
		rc = pinctrl_select_state(led->pinctrl,
						led->gpio_state_active);
@@ -1523,13 +1640,8 @@ exit_flash_led_work:
		goto exit_flash_led_work;
	}
error_enable_gpio:
	if (flash_node->boost_regulator && flash_node->flash_on) {
		regulator_disable(flash_node->boost_regulator);
error_regulator_enable:
		if (regulator_count_voltages(flash_node->boost_regulator) > 0)
			regulator_set_voltage(flash_node->boost_regulator,
				0, flash_node->boost_voltage_max);
	}
	if (flash_node->flash_on && flash_node->num_regulators > 0)
		flash_regulator_enable(led, flash_node, false);

	flash_node->flash_on = false;
	mutex_unlock(&led->flash_led_lock);
@@ -1821,34 +1933,13 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
	return 0;
}

/*
 * Boost regulator probes later than flash.
 * Delay 2s to make sure it has been registered.
 */
static void qpnp_flash_led_delayed_reg_work(struct work_struct *work)
{
	struct flash_node_data *flash_node = container_of(work,
					struct flash_node_data, dwork.work);
	int rc;

	flash_node->boost_regulator = regulator_get(flash_node->cdev.dev,
								"boost");
	if (IS_ERR(flash_node->boost_regulator)) {
		rc = PTR_ERR(flash_node->boost_regulator);
		flash_node->boost_regulator = NULL;
		pr_err("boost regulator get failed\n");
		return;
	}

	return;
}

static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
					struct flash_node_data *flash_node)
{
	const char *temp_string;
	struct device_node *node = flash_node->cdev.dev->of_node;
	int rc = 0;
	struct device_node *temp = NULL;
	int rc = 0, num_regs = 0;
	u32 val;

	rc = of_property_read_string(node, "label", &temp_string);
@@ -1914,31 +2005,14 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
		dev_err(&led->spmi_dev->dev, "Invalid peripheral type\n");
	}

	if (of_find_property(node, "boost-supply", NULL)) {
		INIT_DELAYED_WORK(&flash_node->dwork,
					qpnp_flash_led_delayed_reg_work);

		flash_node->boost_regulator =
				regulator_get(flash_node->cdev.dev, "boost");
		if (!flash_node->boost_regulator ||
				IS_ERR(flash_node->boost_regulator))
			schedule_delayed_work(&flash_node->dwork,
					FLASH_BOOST_REGULATOR_PROBE_DELAY_MS);

		rc = of_property_read_u32(node, "boost-voltage-max", &val);
		if (!rc)
			flash_node->boost_voltage_max = val;
		else {
			dev_err(&led->spmi_dev->dev,
			"Unable to read maximum boost regulator voltage\n");
			goto error_regulator_config;
		}
	while ((temp = of_get_next_child(node, temp))) {
		if (of_find_property(temp, "regulator-name", NULL))
			num_regs++;
	}

	return rc;
	if (num_regs)
		flash_node->num_regulators = num_regs;

error_regulator_config:
	regulator_put(flash_node->boost_regulator);
	return rc;
}

@@ -2351,6 +2425,24 @@ static int qpnp_flash_led_probe(struct spmi_device *spmi)
			goto error_led_register;
		}

		if (&led->flash_node[i].num_regulators) {
			rc = flash_regulator_parse_dt(led, &led->flash_node[i]);
			if (rc) {
				dev_err(&led->spmi_dev->dev,
					"Unable to parse regulator data\n");
				goto error_led_register;
			}

			rc = flash_regulator_setup(led, &led->flash_node[i],
									true);
			if (rc) {
				dev_err(&led->spmi_dev->dev,
					"Unable to set up regulator\n");
				goto error_led_register;
			}

		}

		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
			rc =
			sysfs_create_file(&led->flash_node[i].cdev.dev->kobj,
@@ -2370,7 +2462,7 @@ static int qpnp_flash_led_probe(struct spmi_device *spmi)
			(long)root);
		if (PTR_ERR(root) == -ENODEV)
			pr_err("debugfs is not enabled in kernel");
		goto error_led_register;
		goto error_led_debugfs;
	}

	led->dbgfs_root = root;
@@ -2378,27 +2470,30 @@ static int qpnp_flash_led_probe(struct spmi_device *spmi)
					led, &flash_led_dfs_dbg_feature_fops);
	if (!file) {
		pr_err("error creating 'enable_debug' entry\n");
		goto error_led_register;
		goto error_led_debugfs;
	}

	file = debugfs_create_file("latched", S_IRUSR | S_IWUSR, root, led,
					&flash_led_dfs_latched_reg_fops);
	if (!file) {
		pr_err("error creating 'latched' entry\n");
		goto error_led_register;
		goto error_led_debugfs;
	}

	file = debugfs_create_file("strobe", S_IRUSR | S_IWUSR, root, led,
					&flash_led_dfs_strobe_reg_fops);
	if (!file) {
		pr_err("error creating 'strobe' entry\n");
		goto error_led_register;
		goto error_led_debugfs;
	}

	dev_set_drvdata(&spmi->dev, led);

	return 0;

error_led_debugfs:
	i = led->num_leds - 1;
	j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
error_led_register:
	for (; i >= 0; i--) {
		for (; j >= 0; j--)
@@ -2420,8 +2515,13 @@ static int qpnp_flash_led_remove(struct spmi_device *spmi)
	int i, j;

	for (i = led->num_leds - 1; i >= 0; i--) {
		if (led->flash_node[i].boost_regulator)
			regulator_put(led->flash_node[i].boost_regulator);
		if (led->flash_node[i].reg_data) {
			if (led->flash_node[i].flash_on)
				flash_regulator_enable(led,
						&led->flash_node[i], false);
			flash_regulator_setup(led, &led->flash_node[i],
								false);
		}
		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
			sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
						&qpnp_flash_led_attrs[j].attr);