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

Unverified Commit bb0ac6ee authored by derfelot's avatar derfelot
Browse files

leds: Add Sony led modifications

Taken from Sony 47.2.A.10.107 stock kernel
parent 7108a370
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ Optional properties:
- qcom,thermal-derate-current	: Array of currrent limits for thermal mitigation. Required if
				  qcom,thermal-derate-en is specified. Unit is mA. Format is
				  qcom,thermal-derate-current = <OTST1_LIMIT, OTST2_LIMIT, OTST3_LIMIT>.
				  0, 15, 30, 45 for pmi8998.
- qcom,otst-ramp-back-up-dis	: Boolean property to disable current ramp
				  backup after thermal derate trigger is
				  deasserted.
+7 −0
Original line number Diff line number Diff line
@@ -624,6 +624,13 @@ config LEDS_QPNP_WLED
	  variable brightness.  It also supports outputting the Avdd supply for
	  AMOLED displays.

config LEDS_QPNP_RGB_SCALE
	bool "Support for QPNP RGB LED brightness scale"
	depends on LEDS_QPNP
	default n
	help
	  Adds kernel support for scaling the RGB LED brightness.

config LEDS_SYSCON
	bool "LED support for LEDs on system controllers"
	depends on LEDS_CLASS=y
+208 −3
Original line number Diff line number Diff line
@@ -9,6 +9,11 @@
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#define pr_fmt(fmt)	"flashv2: %s: " fmt, __func__

@@ -101,6 +106,7 @@
#define	VPH_DROOP_HYST_MV_TO_VAL(val_mv)	(val_mv / 25)
#define	VPH_DROOP_THRESH_VAL_TO_UV(val)		((val + 25) * 100000)
#define	MITIGATION_THRSH_MA_TO_VAL(val_ma)	(val_ma / 100)
#define	SAFETY_TMR_TO_REG_VAL(duration_ms)	((duration_ms / 10) - 1)
#define	THERMAL_HYST_TEMP_TO_VAL(val, divisor)	(val / divisor)

#define	FLASH_LED_ISC_WARMUP_DELAY_SHIFT	6
@@ -203,6 +209,7 @@ struct flash_node_data {
	int				current_ma;
	int				prev_current_ma;
	u8				duration;
	int				duration_ms;
	u8				id;
	u8				type;
	u8				ires_idx;
@@ -1360,9 +1367,149 @@ static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
	return snprintf(buf, PAGE_SIZE, "%d\n", max_current);
}

/* sysfs show function for flash_led_fault_status */
static ssize_t qpnp_flash_led_fault_status_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct flash_switch_data *snode;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	struct qpnp_flash_led *led;
	int rc;
	uint val;

	snode = container_of(led_cdev, struct flash_switch_data, cdev);
	led = dev_get_drvdata(&snode->pdev->dev);

	rc = regmap_read(led->regmap,
			FLASH_LED_REG_LED_STATUS1(led->base), &val);
	if (rc) {
		pr_err("Unable to read fault status rc(%d)\n", rc);
		return rc;
	}
	return scnprintf(buf, PAGE_SIZE, "%d\n", val);
}

/* sysfs store function for flash strobe */
static ssize_t qpnp_flash_led_strobe_type_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct flash_node_data *fnode;
	unsigned long state;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	ssize_t ret = -EINVAL;

	ret = kstrtoul(buf, 10, &state);
	if (ret)
		return ret;

	fnode = container_of(led_cdev, struct flash_node_data, cdev);

	/* '0' for sw strobe; '1' for hw strobe */
	if (state == 1)
		fnode->strobe_ctrl |= FLASH_LED_HW_SW_STROBE_SEL_BIT;
	else
		fnode->strobe_ctrl &= ~FLASH_LED_HW_SW_STROBE_SEL_BIT;

	return count;
}

/* sysfs show function for flash duration */
static ssize_t qpnp_flash_led_duration_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct qpnp_flash_led *led;
	struct flash_node_data *flash_node;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);

	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
	led = dev_get_drvdata(&flash_node->pdev->dev);

	return scnprintf(buf, PAGE_SIZE, "%d\n", flash_node->duration_ms);
}

/* sysfs store function for flash duration */
static ssize_t qpnp_flash_led_duration_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct qpnp_flash_led *led;
	struct flash_node_data *flash_node;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	ssize_t ret;
	unsigned long state;

	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
	led = dev_get_drvdata(&flash_node->pdev->dev);

	ret = kstrtoul(buf, 10, &state);
	if (ret)
		return ret;

	flash_node->duration_ms = state;
	flash_node->duration = (u8)(SAFETY_TMR_TO_REG_VAL(flash_node->duration_ms) |
					FLASH_LED_SAFETY_TMR_ENABLE);

	return count;
}

/* sysfs show function for flash ires_ua */
static ssize_t qpnp_flash_led_ires_ua_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct qpnp_flash_led *led;
	struct flash_node_data *flash_node;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);

	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
	led = dev_get_drvdata(&flash_node->pdev->dev);

	return scnprintf(buf, PAGE_SIZE, "%d\n", flash_node->ires_ua);
}

/* sysfs store function for flash ires_ua */
static ssize_t qpnp_flash_led_ires_ua_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct qpnp_flash_led *led;
	struct flash_node_data *flash_node;
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	ssize_t ret;
	unsigned long state;

	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
	led = dev_get_drvdata(&flash_node->pdev->dev);

	ret = kstrtoul(buf, 10, &state);
	if (ret)
		return ret;

	flash_node->default_ires_ua = flash_node->ires_ua = state;
	flash_node->default_ires_idx = flash_node->ires_idx = FLASH_LED_IRES_BASE -
			(flash_node->ires_ua - FLASH_LED_IRES_MIN_UA) / FLASH_LED_IRES_DIVISOR;

	return count;
}

/* sysfs attributes exported by flash_led */
static struct device_attribute qpnp_flash_led_attrs[] = {
	__ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL),
	__ATTR(fault_status, S_IRUSR | S_IRGRP,
				qpnp_flash_led_fault_status_show,
				NULL),
};

static struct device_attribute qpnp_flash_fnode_attrs[] = {
	__ATTR(strobe, (S_IRUGO | S_IWUSR | S_IWGRP),
				NULL,
				qpnp_flash_led_strobe_type_store),
	__ATTR(duration, (S_IRUGO | S_IWUSR | S_IWGRP),
				qpnp_flash_led_duration_show,
				qpnp_flash_led_duration_store),
	__ATTR(ires_ua, (S_IRUGO | S_IWUSR | S_IWGRP),
				qpnp_flash_led_ires_ua_show,
				qpnp_flash_led_ires_ua_store),
};

static int flash_led_psy_notifier_call(struct notifier_block *nb,
@@ -1575,6 +1722,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
	fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
	rc = of_property_read_u32(node, "qcom,duration-ms", &val);
	if (!rc) {
		fnode->duration_ms = val;
		fnode->duration = get_safety_timer_code(val);
		if (fnode->duration)
			fnode->duration |= FLASH_LED_SAFETY_TMR_ENABLE;
@@ -1648,7 +1796,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
						"qcom,hw-strobe-edge-trigger");
		active_high = !of_property_read_bool(node,
						"qcom,hw-strobe-active-low");
		hw_strobe = 1;
		hw_strobe = !of_property_read_bool(node, "somc,sw-strobe-init");
	} else if (fnode->strobe_sel == LPG_STROBE) {
		/* LPG strobe requires level trigger and active high */
		edge_trigger = 0;
@@ -1751,7 +1899,8 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
		if (IS_ERR_OR_NULL(snode->vreg)) {
			rc = PTR_ERR(snode->vreg);
			if (rc != -EPROBE_DEFER)
				pr_err("Failed to get regulator, rc=%d\n", rc);
				dev_err(&led->pdev->dev, "Failed to get regulator, rc=%d\n",
					rc);
			snode->vreg = NULL;
			return rc;
		}
@@ -2210,6 +2359,29 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
	return 0;
}

static int qpnp_flash_led_init_strobe_settings(struct qpnp_flash_led *led)
{
	int rc = 0, i, addr_offset;

	rc = qpnp_flash_led_masked_write(led,
					FLASH_LED_REG_STROBE_CFG(led->base),
					FLASH_LED_STROBE_MASK,
					led->pdata->hw_strobe_option);
	if (rc < 0)
		return rc;

	for (i = 0; i < led->num_fnodes; i++) {
		addr_offset = led->fnode[i].id;
		rc = qpnp_flash_led_masked_write(led,
			FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
			FLASH_LED_STROBE_MASK, led->fnode[i].strobe_ctrl);
		if (rc < 0)
			return rc;
	}

	return rc;
}

static int qpnp_flash_led_probe(struct platform_device *pdev)
{
	struct qpnp_flash_led *led;
@@ -2380,6 +2552,23 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
		goto unreg_notifier;
	}

	rc = qpnp_flash_led_init_strobe_settings(led);
	if (rc < 0) {
		pr_err("Failed to initialize flash strobe, rc=%d\n", rc);
		goto unreg_notifier;
	}

	for (i = 0; i < led->num_fnodes; i++) {
		for (j = 0; j < ARRAY_SIZE(qpnp_flash_fnode_attrs); j++) {
			rc = sysfs_create_file(&led->fnode[i].cdev.dev->kobj,
					&qpnp_flash_fnode_attrs[j].attr);
			if (rc < 0) {
				pr_err("sysfs creation failed, rc=%d\n", rc);
				goto sysfs_fnode_fail;
			}
		}
	}

	for (i = 0; i < led->num_snodes; i++) {
		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
			rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj,
@@ -2397,6 +2586,16 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)

	return 0;

sysfs_fnode_fail:
	for (--j; j >= 0; j--)
		sysfs_remove_file(&led->fnode[i].cdev.dev->kobj,
				&qpnp_flash_fnode_attrs[j].attr);

	for (--i; i >= 0; i--) {
		for (j = 0; j < ARRAY_SIZE(qpnp_flash_fnode_attrs); j++)
			sysfs_remove_file(&led->fnode[i].cdev.dev->kobj,
					&qpnp_flash_fnode_attrs[j].attr);
	}
sysfs_fail:
	for (--j; j >= 0; j--)
		sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
@@ -2407,7 +2606,6 @@ sysfs_fail:
			sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
					&qpnp_flash_led_attrs[j].attr);
	}

	i = led->num_snodes;
unreg_notifier:
	power_supply_unreg_notifier(&led->nb);
@@ -2441,6 +2639,13 @@ static int qpnp_flash_led_remove(struct platform_device *pdev)
		led_classdev_unregister(&led->snode[--i].cdev);

	i = led->num_fnodes;

	for (i = 0; i < led->num_fnodes; i++) {
		for (j = 0; j < ARRAY_SIZE(qpnp_flash_fnode_attrs); j++)
			sysfs_remove_file(&led->fnode[i].cdev.dev->kobj,
					&qpnp_flash_fnode_attrs[j].attr);
	}

	while (i > 0)
		led_classdev_unregister(&led->fnode[--i].cdev);

+353 −25
Original line number Diff line number Diff line
@@ -9,6 +9,11 @@
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#include <linux/module.h>
#include <linux/init.h>
@@ -237,6 +242,13 @@
#define QPNP_WLED_AVDD_MV_TO_REG(val) \
		((val - QPNP_WLED_AVDD_MIN_MV) / QPNP_WLED_AVDD_STEP_MV)

#define QPNP_WLED_CURR_SCALE_MAX	100
#define QPNP_WLED_BL_SCALE_MAX	1000
#define QPNP_WLED_BUFF_SIZE	128

#define BR_MAX_FIGURE	9
#define AREA_COUNT_MAX	9999999

/* output feedback mode */
enum qpnp_wled_fdbk_op {
	QPNP_WLED_FDBK_AUTO,
@@ -311,6 +323,12 @@ static struct wled_vref_setting vref_setting_pmi8998 = {
	60000, 397500, 22500, 127500,
};

static unsigned long *area_count;
static int *area_count_table;
static int area_count_table_size;
static int now_area;
static unsigned long start_jiffies;

/**
 *  qpnp_wled - wed data structure
 *  @ cdev - led class device
@@ -424,8 +442,24 @@ struct qpnp_wled {
	bool			auto_calib_done;
	bool			module_dis_perm;
	ktime_t			start_ovp_fault_time;
	int init_br_ua;
	bool bl_scale_enabled;
	int bl_scale;
	bool calc_curr;
	int curr_scale;
};

static bool bl_on_in_boot;
static int __init continous_splash_setup(char *str)
{
	if (!str)
		return 0;
	if (!strncmp(str, "on", 2))
		bl_on_in_boot = true;
	return 0;
}
__setup("display_status=", continous_splash_setup);

static int qpnp_wled_step_delay_us = 52000;
module_param_named(
	total_step_delay_us, qpnp_wled_step_delay_us, int, 0600
@@ -574,10 +608,20 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
	u8 reg;
	u16 low_limit = WLED_MAX_LEVEL_4095 * 4 / 1000;

	if (wled->calc_curr &&
		wled->curr_scale != QPNP_WLED_CURR_SCALE_MAX)
		level = level * wled->curr_scale / QPNP_WLED_CURR_SCALE_MAX;

	if (wled->bl_scale_enabled && wled->bl_scale > 0 &&
		wled->bl_scale < QPNP_WLED_BL_SCALE_MAX)
		level = level * wled->bl_scale / QPNP_WLED_BL_SCALE_MAX;

	/* WLED's lower limit of operation is 0.4% */
	if (level > 0 && level < low_limit)
		level = low_limit;

	pr_debug("%s: brightness=%d level=%d\n",
			__func__, wled->cdev.brightness, level);
	/* set brightness registers */
	for (i = 0; i < wled->max_strings; i++) {
		reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
@@ -1025,6 +1069,10 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
		else if (data > QPNP_WLED_FS_CURR_MAX_UA)
			data = QPNP_WLED_FS_CURR_MAX_UA;

		if (wled->calc_curr)
			reg = (data + (QPNP_WLED_FS_CURR_STEP_UA - 1)) /
				QPNP_WLED_FS_CURR_STEP_UA;
		else
			reg = data / QPNP_WLED_FS_CURR_STEP_UA;
		rc = qpnp_wled_masked_write_reg(wled,
			QPNP_WLED_FS_CURR_REG(wled->sink_base, i),
@@ -1044,6 +1092,148 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
	return count;
}

static ssize_t qpnp_wled_bl_scale_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct qpnp_wled *wled = dev_get_drvdata(dev);
	if (!wled->bl_scale_enabled)
		wled->bl_scale = QPNP_WLED_BL_SCALE_MAX;
	dev_dbg(&wled->pdev->dev, "%s: bl_scale = %d\n", __func__, wled->bl_scale);

	return snprintf(buf, QPNP_WLED_BUFF_SIZE, "%u\n", wled->bl_scale);
}

static ssize_t qpnp_wled_bl_scale_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct qpnp_wled *wled = dev_get_drvdata(dev);
	unsigned long scale = 0;
	ssize_t ret = -EINVAL;

	if (!wled->bl_scale_enabled) {
		wled->bl_scale = QPNP_WLED_BL_SCALE_MAX;
		dev_err(&wled->pdev->dev, "Sysfs bl_scale is not enabled\n");
		goto exit;
	}

	ret = kstrtoul(buf, 10, &scale);
	if (!ret) {
		ret = size;
		if (scale > QPNP_WLED_BL_SCALE_MAX)
			scale = QPNP_WLED_BL_SCALE_MAX;
		wled->bl_scale = scale;
		dev_dbg(&wled->pdev->dev, "%s: bl_scale = %d\n", __func__, wled->bl_scale);
	} else {
		dev_err(&wled->pdev->dev, "Failure to set sysfs bl_scale\n");
		ret = -EINVAL;
	}

exit:
	return ret;
}

static void update_areacount(int new_area)
{
	unsigned long now;
	unsigned long duration;

	now = jiffies;
	duration = (now - start_jiffies) >= 0 ?
			(now - start_jiffies) : (now + start_jiffies);
	area_count[now_area] = area_count[now_area]
			+ jiffies_to_msecs(duration);

	now_area = new_area;
	start_jiffies = now;
}

static ssize_t qpnp_wled_area_count_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct qpnp_wled *wled = dev_get_drvdata(dev);
	int i;
	char area_count_str[QPNP_WLED_BUFF_SIZE];
	char count_data[BR_MAX_FIGURE];

	if (!area_count_table_size)
		return snprintf(buf, QPNP_WLED_BUFF_SIZE, "area_count is not supported\n");

	mutex_lock(&wled->cdev.led_access);
	/* fixed statistics */
	update_areacount(now_area);

	memset(area_count_str, 0, sizeof(char) * QPNP_WLED_BUFF_SIZE);
	for (i = 0; i < area_count_table_size; i++) {
		dev_dbg(&wled->pdev->dev, "%ld, ", area_count[i]);
		memset(count_data, 0, sizeof(char) * BR_MAX_FIGURE);
		if (area_count[i] > AREA_COUNT_MAX) {
			/* over 167 min */
			area_count[i] = AREA_COUNT_MAX;
		}
		if (i == 0) {
			snprintf(count_data, BR_MAX_FIGURE,
				"%ld", area_count[i]);
			strlcpy(area_count_str, count_data, QPNP_WLED_BUFF_SIZE);
		} else {
			snprintf(count_data, BR_MAX_FIGURE,
				",%ld", area_count[i]);
			strlcat(area_count_str, count_data, QPNP_WLED_BUFF_SIZE);
		}
	}

	memset(area_count, 0, sizeof(unsigned long) * area_count_table_size);
	mutex_unlock(&wled->cdev.led_access);

	return snprintf(buf, QPNP_WLED_BUFF_SIZE, "%s\n", area_count_str);
}

static ssize_t qpnp_wled_en_cabc_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct qpnp_wled *wled = dev_get_drvdata(dev);
	char *str = wled->en_cabc ? "true" : "false";

	dev_dbg(&wled->pdev->dev, "%s: en_cabc:%s\n", __func__, str);

	return snprintf(buf, QPNP_WLED_BUFF_SIZE, "%s\n", str);
}

static ssize_t qpnp_wled_en_cabc_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct qpnp_wled *wled = dev_get_drvdata(dev);
	int data, i, rc;
	u8 reg, mask;

	rc = kstrtoint(buf, 10, &data);
	if (rc)
		return rc;

	if (data)
		wled->en_cabc = true;
	else
		wled->en_cabc = false;

	pr_info("%s: set wled->en_cabc:%d\n",  __func__, wled->en_cabc);
	for (i = 0; i < wled->num_strings; i++) {
		reg = wled->en_cabc ? (1  << QPNP_WLED_CABC_SHIFT) : 0;
		mask = QPNP_WLED_CABC_MASK;
		rc = qpnp_wled_masked_write_reg(wled,
			QPNP_WLED_CABC_REG(wled->sink_base, i),
			mask, reg);
		if (rc < 0)
			return rc;
	}

	rc = qpnp_wled_sync_reg_toggle(wled);
	if (rc < 0) {
		dev_err(&wled->pdev->dev, "Failed to toggle sync reg %d\n", rc);
		return rc;
	}

	return size;
}

/* sysfs attributes exported by wled */
static struct device_attribute qpnp_wled_attrs[] = {
	__ATTR(dump_regs, 0664, qpnp_wled_dump_regs_show, NULL),
@@ -1055,8 +1245,42 @@ static struct device_attribute qpnp_wled_attrs[] = {
	__ATTR(ramp_ms, 0664, qpnp_wled_ramp_ms_show, qpnp_wled_ramp_ms_store),
	__ATTR(ramp_step, 0664, qpnp_wled_ramp_step_show,
		qpnp_wled_ramp_step_store),
	__ATTR(bl_scale, (S_IRUGO | S_IWUSR | S_IWGRP),
			qpnp_wled_bl_scale_show,
			qpnp_wled_bl_scale_store),
	__ATTR(area_count, (S_IRUSR | S_IRGRP),
			qpnp_wled_area_count_show,
			NULL),
	__ATTR(en_cabc, (S_IRUGO | S_IWUSR | S_IWGRP),
			qpnp_wled_en_cabc_show,
			qpnp_wled_en_cabc_store),
};

static int get_area(int level)
{
	int i;

	for (i = 0; i < area_count_table_size; i++) {
		if (i == 0) {
			if (level == area_count_table[i])
				break;
		} else {
			if (level <= area_count_table[i])
				break;
		}
	}

	return i;
}

static void qpnp_wled_update_area(int level)
{
	int new_area = get_area(level);

	if (now_area != new_area)
		update_areacount(new_area);
}

/* worker for setting wled brightness */
static void qpnp_wled_work(struct work_struct *work)
{
@@ -1067,6 +1291,7 @@ static void qpnp_wled_work(struct work_struct *work)

	mutex_lock(&wled->lock);
	level = wled->cdev.brightness;
	qpnp_wled_update_area(level);

	if (wled->brt_map_table) {
		/*
@@ -1115,6 +1340,7 @@ static void qpnp_wled_work(struct work_struct *work)
						level ? "en" : "dis");
			goto unlock_mutex;
		}
		usleep_range(100, 101);
	}

	wled->prev_state = !!level;
@@ -2072,6 +2298,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
	if (rc)
		return rc;

	if (!bl_on_in_boot) {
		/* disable all current sinks and enable selected strings */
		reg = 0x00;
		rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base),
@@ -2101,6 +2328,10 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
			mask, reg);
			if (rc < 0)
				return rc;
			if (wled->calc_curr)
				temp = (wled->fs_curr_ua + (QPNP_WLED_FS_CURR_STEP_UA - 1)) /
					QPNP_WLED_FS_CURR_STEP_UA;
			else

			/* CABC */
		reg = wled->en_cabc ? (1  << QPNP_WLED_CABC_SHIFT) : 0;
@@ -2149,6 +2380,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
			"Failed to enable WLED sink config rc = %d\n", rc);
		return rc;
		}
	}

	rc = qpnp_wled_sync_reg_toggle(wled);
	if (rc < 0) {
@@ -2245,6 +2477,39 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
	return 0;
}

static void qpnp_wled_set_init_br(struct qpnp_wled *wled)
{
	int calc_init_br;
	if (wled->fs_curr_ua) {
		calc_init_br = (wled->cdev.max_brightness * wled->init_br_ua)
			/ wled->fs_curr_ua;
	} else {
		calc_init_br = (wled->cdev.max_brightness * wled->init_br_ua)
			/ QPNP_WLED_FS_CURR_MAX_UA;
	}
	qpnp_wled_set(&wled->cdev, calc_init_br);
}

static int qpnp_wled_set_scale(struct qpnp_wled *wled)
{
	u8 reg = 0;
	int rc, curr;

	wled->curr_scale = QPNP_WLED_CURR_SCALE_MAX;
	rc = qpnp_wled_read_reg(wled, QPNP_WLED_FS_CURR_REG(wled->sink_base,
				wled->strings[0]), &reg);
	if (rc)
		return rc;
	reg &= QPNP_WLED_FS_CURR_MASK;
	curr = reg * QPNP_WLED_FS_CURR_STEP_UA;
	if (curr > wled->fs_curr_ua)
		wled->curr_scale = (wled->fs_curr_ua *
			QPNP_WLED_CURR_SCALE_MAX) / curr;
	dev_dbg(&wled->pdev->dev, "%s: curr = %d fs_curr_ua = %d curr_scale = %d\n",
		__func__, curr, wled->fs_curr_ua, wled->curr_scale);
	return 0;
}

/* parse wled dtsi parameters */
static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
{
@@ -2575,6 +2840,10 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
	if (!rc)
		wled->cons_sync_write_delay_us = temp_val;

	wled->calc_curr = of_property_read_bool(pdev->dev.of_node,
			"somc,calc-curr");
	wled->bl_scale_enabled = of_property_read_bool(pdev->dev.of_node,
			"somc,bl-scale-enabled");
	wled->en_9b_dim_res = of_property_read_bool(pdev->dev.of_node,
			"qcom,en-9b-dim-res");
	wled->en_phase_stag = of_property_read_bool(pdev->dev.of_node,
@@ -2617,6 +2886,50 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)

	wled->auto_calib_enabled = of_property_read_bool(pdev->dev.of_node,
					"qcom,auto-calibration-enable");
	wled->init_br_ua = LED_OFF;
	rc = of_property_read_u32(pdev->dev.of_node,
					"somc,init-br-ua", &temp_val);
	if (!rc) {
		wled->init_br_ua = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&pdev->dev, "Unable to read init ua\n");
		return rc;
	}

	rc = of_property_read_u32(pdev->dev.of_node,
			"somc,area_count_table_size", &temp_val);
	if (!rc) {
		area_count_table_size = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&pdev->dev, "Unable to read area_count_table_size\n");
		return rc;
	}

	if (area_count_table_size > 0) {
		area_count_table = devm_kzalloc(&pdev->dev,
			sizeof(int) * area_count_table_size, GFP_KERNEL);
		if (!area_count_table)
			return -ENOMEM;

		area_count = devm_kzalloc(&pdev->dev,
			sizeof(unsigned long) * area_count_table_size, GFP_KERNEL);
		if (!area_count_table)
			return -ENOMEM;

		rc = of_property_read_u32_array(pdev->dev.of_node, "somc,area_count_table",
					area_count_table, area_count_table_size);
		if (rc < 0) {
			dev_err(&pdev->dev, "Unable to read somc,area_count_table\n");
			temp_val = (WLED_MAX_LEVEL_4095 % (area_count_table_size - 1) > 0 ?
				((WLED_MAX_LEVEL_4095 / (area_count_table_size - 1)) + 1) :
				(WLED_MAX_LEVEL_4095 / (area_count_table_size - 1)));
			area_count_table[0] = 0;
			for (i = 1; i < area_count_table_size; i++) {
				area_count_table[i] = temp_val * i;
			}
		}
	}

	return 0;
}

@@ -2698,6 +3011,14 @@ static int qpnp_wled_probe(struct platform_device *pdev)
		return rc;
	}

	if (wled->calc_curr) {
		rc = qpnp_wled_set_scale(wled);
		if (rc) {
			dev_err(&pdev->dev, "wled config failed\n");
			return rc;
		}
	}

	INIT_WORK(&wled->work, qpnp_wled_work);
	wled->ramp_ms = QPNP_WLED_RAMP_DLY_MS;
	wled->ramp_step = 1;
@@ -2706,6 +3027,8 @@ static int qpnp_wled_probe(struct platform_device *pdev)
	wled->cdev.brightness_get = qpnp_wled_get;

	wled->cdev.max_brightness = WLED_MAX_LEVEL_4095;
	now_area = 0;
	start_jiffies = jiffies;

	rc = led_classdev_register(&pdev->dev, &wled->cdev);
	if (rc) {
@@ -2722,6 +3045,9 @@ static int qpnp_wled_probe(struct platform_device *pdev)
		}
	}

	if (wled->init_br_ua && !bl_on_in_boot)
		qpnp_wled_set_init_br(wled);

	return 0;

sysfs_fail:
@@ -2748,6 +3074,8 @@ static int qpnp_wled_remove(struct platform_device *pdev)
	led_classdev_unregister(&wled->cdev);
	cancel_work_sync(&wled->work);
	destroy_workqueue(wled->wq);
	devm_kfree(&pdev->dev, area_count_table);
	devm_kfree(&pdev->dev, area_count);
	mutex_destroy(&wled->lock);

	return 0;
+773 −5

File changed.

Preview size limit exceeded, changes collapsed.

Loading