Merge "leds: qpnp-flash-v2: Add support for led_fault_irq"

This commit is contained in:
Linux Build Service Account 2016-08-01 21:56:35 -07:00 committed by Gerrit - the friendly Code Review server
commit 25070b2a8d
7 changed files with 459 additions and 31 deletions

View file

@ -13,9 +13,25 @@ Required properties:
- reg : Base address and size for flash LED modules
Optional properties:
- interrupts : Specifies the interrupts associated with flash-led.
- interrupt-names : Specify the interrupt names associated with interrupts.
- qcom,hdrm-auto-mode : Boolean type to select headroom auto mode enabled or not
- qcom,isc-delay : Integer type to specify short circuit delay. Valid values are 32, 64,
128, 192. Unit is us.
- qcom,isc-delay-us : Integer type to specify short circuit delay. Valid values are 32, 64,
128, 192. Unit is uS.
- qcom,warmup-delay-us : Integer type to specify warm up delay. Valid values are 32, 64,
128, 192. Unit is uS.
- qcom,short-circuit-det : Boolean property which enables short circuit fault detection.
- qcom,open-circuit-det : Boolean property which enables open circuit fault detection.
- qcom,vph-droop-det : Boolean property which enables VPH droop detection.
- qcom,vph-droop-hys-mv : Integer property to specify VPH droop hysteresis. It is only used if
qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75.
Unit is mV.
- qcom,vph-droop-thresh-mv : Integer property to specify VPH droop threshold. It is only used if
qcom,vph-droop-det is specified. Valid values are
2500 to 3200 with step size of 100. Unit is mV.
- qcom,vph-droop-debounce-us : Integer property to specify VPH droop debounce time. It is only used
if qcom,vph-droop-det is specified. Valid values are 0, 8, 16 and 26.
Unit is uS.
- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified
value, additional GPIO configuration may be required to provide strobing
support. Supported values are:
@ -93,6 +109,22 @@ Example:
status = "okay";
reg = <0xd300 0x100>;
label = "flash";
interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x1 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x2 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x3 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x5 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x6 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xd3 0x7 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "led-fault-irq",
"mitigation-irq",
"flash-timer-exp-irq",
"all-ramp-down-done-irq",
"all-ramp-up-done-irq",
"led3-ramp-up-done-irq",
"led2-ramp-up-done-irq",
"led1-ramp-up-done-irq";
qcom,hdrm-auto-mode;
qcom,isc-delay = <192>;

View file

@ -634,6 +634,10 @@
status = "okay";
reg = <0xd300 0x100>;
label = "flash";
interrupts = <0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>,
<0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "all-ramp-down-done-irq",
"all-ramp-up-done-irq";
qcom,hdrm-auto-mode;
qcom,isc-delay = <192>;

View file

@ -16,13 +16,20 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/leds-qpnp-flash.h>
#include <linux/leds-qpnp-flash-v2.h>
#include "leds.h"
#define FLASH_LED_REG_LED_STATUS1(base) (base + 0x08)
#define FLASH_LED_REG_LED_STATUS2(base) (base + 0x09)
#define FLASH_LED_REG_INT_RT_STS(base) (base + 0x10)
#define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40)
#define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43)
#define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46)
@ -32,20 +39,40 @@
#define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C)
#define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D)
#define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
#define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51)
#define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
#define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61)
#define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62)
#define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76)
#define FLASH_LED_HDRM_MODE_PRGM_MASK GENMASK(7, 0)
#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
#define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
#define FLASH_LED_ENABLE_MASK GENMASK(2, 0)
#define FLASH_LED_SAFETY_TMR_MASK GENMASK(7, 0)
#define FLASH_LED_ISC_DELAY_MASK GENMASK(1, 0)
#define FLASH_LED_INT_RT_STS_MASK GENMASK(7, 0)
#define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
#define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0)
#define FLASH_LED_VPH_DROOP_DEBOUNCE_MASK GENMASK(1, 0)
#define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4)
#define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0)
#define FLASH_LED_MOD_CTRL_MASK BIT(7)
#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2)
#define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
#define FLASH_LED_HEADROOM_AUTO_MODE_ENABLED true
#define FLASH_LED_ISC_DELAY_SHIFT 6
#define FLASH_LED_ISC_DELAY_DEFAULT_US 3
#define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8)
#define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25)
#define VPH_DROOP_THRESH_MV_TO_VAL(val_mv) ((val_mv / 100) - 25)
#define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6
#define FLASH_LED_WARMUP_DELAY_DEFAULT 2
#define FLASH_LED_ISC_DELAY_DEFAULT 3
#define FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT 2
#define FLASH_LED_VPH_DROOP_HYST_DEFAULT 2
#define FLASH_LED_VPH_DROOP_THRESH_DEFAULT 5
#define FLASH_LED_VPH_DROOP_DEBOUNCE_MAX 3
#define FLASH_LED_VPH_DROOP_HYST_MAX 3
#define FLASH_LED_VPH_DROOP_THRESH_MAX 7
#define FLASH_LED_SAFETY_TMR_VAL_OFFSET 1
#define FLASH_LED_SAFETY_TMR_VAL_DIVISOR 10
#define FLASH_LED_SAFETY_TMR_ENABLE BIT(7)
@ -69,6 +96,9 @@
#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
#define FLASH_LED_MIN_CURRENT_MA 25
/* notifier call chain for flash-led irqs */
static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
enum flash_led_type {
FLASH_LED_TYPE_FLASH,
FLASH_LED_TYPE_TORCH,
@ -125,7 +155,15 @@ struct flash_switch_data {
* Flash LED configuration read from device tree
*/
struct flash_led_platform_data {
u8 isc_delay_us;
int all_ramp_up_done_irq;
int all_ramp_down_done_irq;
int led_fault_irq;
u8 isc_delay;
u8 warmup_delay;
u8 current_derate_en_cfg;
u8 vph_droop_threshold;
u8 vph_droop_hysteresis;
u8 vph_droop_debounce;
u8 hw_strobe_option;
bool hdrm_auto_mode_en;
};
@ -146,6 +184,24 @@ struct qpnp_flash_led {
u16 base;
};
static int
qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
{
int rc;
uint val;
rc = regmap_read(led->regmap, addr, &val);
if (rc < 0)
dev_err(&led->pdev->dev, "Unable to read from 0x%04X rc = %d\n",
addr, rc);
else
dev_dbg(&led->pdev->dev, "Read 0x%02X from addr 0x%04X\n",
val, addr);
*data = (u8)val;
return rc;
}
static int
qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
u8 val)
@ -154,11 +210,10 @@ qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
rc = regmap_update_bits(led->regmap, addr, mask, val);
if (rc < 0)
dev_err(&led->pdev->dev,
"Unable to update bits from 0x%02X, rc = %d\n",
dev_err(&led->pdev->dev, "Unable to update bits from 0x%04X, rc = %d\n",
addr, rc);
else
dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%02X\n",
dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%04X\n",
val, addr);
return rc;
@ -195,7 +250,43 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_ISC_DELAY(led->base),
FLASH_LED_ISC_DELAY_MASK, led->pdata->isc_delay_us);
FLASH_LED_ISC_WARMUP_DELAY_MASK,
led->pdata->isc_delay);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_WARMUP_DELAY(led->base),
FLASH_LED_ISC_WARMUP_DELAY_MASK,
led->pdata->warmup_delay);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_CURRENT_DERATE_EN(led->base),
FLASH_LED_CURRENT_DERATE_EN_MASK,
led->pdata->current_derate_en_cfg);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base),
FLASH_LED_VPH_DROOP_DEBOUNCE_MASK,
led->pdata->vph_droop_debounce);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
FLASH_LED_VPH_DROOP_THRESHOLD_MASK,
led->pdata->vph_droop_threshold);
if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
FLASH_LED_VPH_DROOP_HYSTERESIS_MASK,
led->pdata->vph_droop_hysteresis);
if (rc < 0)
return rc;
@ -459,13 +550,21 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
return 0;
}
int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options)
int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
{
struct flash_switch_data *snode =
container_of(led_cdev, struct flash_switch_data, cdev);
struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
struct led_classdev *led_cdev = trigger_to_lcdev(trig);
struct flash_switch_data *snode;
struct qpnp_flash_led *led;
int rc, val = 0;
if (!led_cdev) {
pr_err("Invalid led_trigger provided\n");
return -EINVAL;
}
snode = container_of(led_cdev, struct flash_switch_data, cdev);
led = dev_get_drvdata(&snode->pdev->dev);
if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) {
dev_err(&led->pdev->dev, "Invalid options %d\n", options);
return -EINVAL;
@ -521,6 +620,77 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
spin_unlock(&led->lock);
}
/* irq handler */
static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led)
{
struct qpnp_flash_led *led = _led;
enum flash_led_irq_type irq_type = INVALID_IRQ;
int rc;
u8 irq_status, led_status1, led_status2;
dev_dbg(&led->pdev->dev, "irq received, irq=%d\n", irq);
rc = qpnp_flash_led_read(led,
FLASH_LED_REG_INT_RT_STS(led->base), &irq_status);
if (rc < 0) {
dev_err(&led->pdev->dev, "Failed to read interrupt status reg, rc=%d\n",
rc);
goto exit;
}
if (irq == led->pdata->all_ramp_up_done_irq)
irq_type = ALL_RAMP_UP_DONE_IRQ;
else if (irq == led->pdata->all_ramp_down_done_irq)
irq_type = ALL_RAMP_DOWN_DONE_IRQ;
else if (irq == led->pdata->led_fault_irq)
irq_type = LED_FAULT_IRQ;
if (irq_type == ALL_RAMP_UP_DONE_IRQ)
atomic_notifier_call_chain(&irq_notifier_list,
irq_type, NULL);
if (irq_type == LED_FAULT_IRQ) {
rc = qpnp_flash_led_read(led,
FLASH_LED_REG_LED_STATUS1(led->base), &led_status1);
if (rc < 0) {
dev_err(&led->pdev->dev, "Failed to read led_status1 reg, rc=%d\n",
rc);
goto exit;
}
rc = qpnp_flash_led_read(led,
FLASH_LED_REG_LED_STATUS2(led->base), &led_status2);
if (rc < 0) {
dev_err(&led->pdev->dev, "Failed to read led_status2 reg, rc=%d\n",
rc);
goto exit;
}
if (led_status1)
dev_emerg(&led->pdev->dev, "led short/open fault detected! led_status1=%x\n",
led_status1);
if (led_status2 & FLASH_LED_VPH_DROOP_FAULT_MASK)
dev_emerg(&led->pdev->dev, "led vph_droop fault detected!\n");
}
dev_dbg(&led->pdev->dev, "irq handled, irq_type=%x, irq_status=%x\n",
irq_type, irq_status);
exit:
return IRQ_HANDLED;
}
int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&irq_notifier_list, nb);
}
int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&irq_notifier_list, nb);
}
static int qpnp_flash_led_regulator_setup(struct qpnp_flash_led *led,
struct flash_switch_data *snode, bool on)
{
@ -901,28 +1071,116 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
{
int rc;
u32 val;
bool short_circuit_det, open_circuit_det, vph_droop_det;
led->pdata->hdrm_auto_mode_en = FLASH_LED_HEADROOM_AUTO_MODE_ENABLED;
led->pdata->hdrm_auto_mode_en = of_property_read_bool(node,
"qcom,hdrm-auto-mode");
led->pdata->isc_delay_us = FLASH_LED_ISC_DELAY_DEFAULT_US;
rc = of_property_read_u32(node, "qcom,isc-delay", &val);
led->pdata->isc_delay = FLASH_LED_ISC_DELAY_DEFAULT;
rc = of_property_read_u32(node, "qcom,isc-delay-us", &val);
if (!rc) {
led->pdata->isc_delay_us = val >> FLASH_LED_ISC_DELAY_SHIFT;
led->pdata->isc_delay =
val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
} else if (rc != -EINVAL) {
dev_err(&led->pdev->dev, "Unable to read ISC delay\n");
dev_err(&led->pdev->dev,
"Unable to read ISC delay, rc=%d\n", rc);
return rc;
}
led->pdata->warmup_delay = FLASH_LED_WARMUP_DELAY_DEFAULT;
rc = of_property_read_u32(node, "qcom,warmup-delay-us", &val);
if (!rc) {
led->pdata->warmup_delay =
val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
} else if (rc != -EINVAL) {
dev_err(&led->pdev->dev,
"Unable to read WARMUP delay, rc=%d\n", rc);
return rc;
}
short_circuit_det =
of_property_read_bool(node, "qcom,short-circuit-det");
open_circuit_det = of_property_read_bool(node, "qcom,open-circuit-det");
vph_droop_det = of_property_read_bool(node, "qcom,vph-droop-det");
led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
(open_circuit_det << 1) | short_circuit_det;
led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
if (!rc) {
led->pdata->vph_droop_debounce =
VPH_DROOP_DEBOUNCE_US_TO_VAL(val);
} else if (rc != -EINVAL) {
dev_err(&led->pdev->dev,
"Unable to read VPH droop debounce, rc=%d\n", rc);
return rc;
}
if (led->pdata->vph_droop_debounce > FLASH_LED_VPH_DROOP_DEBOUNCE_MAX) {
dev_err(&led->pdev->dev,
"Invalid VPH droop debounce specified");
return -EINVAL;
}
led->pdata->vph_droop_threshold = FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
rc = of_property_read_u32(node, "qcom,vph-droop-threshold-mv", &val);
if (!rc) {
led->pdata->vph_droop_threshold =
VPH_DROOP_THRESH_MV_TO_VAL(val);
} else if (rc != -EINVAL) {
dev_err(&led->pdev->dev,
"Unable to read VPH droop threshold, rc=%d\n", rc);
return rc;
}
if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) {
dev_err(&led->pdev->dev,
"Invalid VPH droop threshold specified");
return -EINVAL;
}
led->pdata->vph_droop_hysteresis =
FLASH_LED_VPH_DROOP_HYST_DEFAULT;
rc = of_property_read_u32(node, "qcom,vph-droop-hysteresis-mv", &val);
if (!rc) {
led->pdata->vph_droop_hysteresis =
VPH_DROOP_HYST_MV_TO_VAL(val);
} else if (rc != -EINVAL) {
dev_err(&led->pdev->dev,
"Unable to read VPH droop hysteresis, rc=%d\n", rc);
return rc;
}
if (led->pdata->vph_droop_hysteresis > FLASH_LED_VPH_DROOP_HYST_MAX) {
dev_err(&led->pdev->dev,
"Invalid VPH droop hysteresis specified");
return -EINVAL;
}
rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
if (!rc) {
led->pdata->hw_strobe_option = (u8)val;
} else if (rc != -EINVAL) {
dev_err(&led->pdev->dev, "Unable to parse hw strobe option\n");
dev_err(&led->pdev->dev,
"Unable to parse hw strobe option, rc=%d\n", rc);
return rc;
}
led->pdata->all_ramp_up_done_irq =
of_irq_get_byname(node, "all-ramp-up-done-irq");
if (led->pdata->all_ramp_up_done_irq < 0)
dev_dbg(&led->pdev->dev, "all-ramp-up-done-irq not used\n");
led->pdata->all_ramp_down_done_irq =
of_irq_get_byname(node, "all-ramp-down-done-irq");
if (led->pdata->all_ramp_down_done_irq < 0)
dev_dbg(&led->pdev->dev, "all-ramp-down-done-irq not used\n");
led->pdata->led_fault_irq =
of_irq_get_byname(node, "led-fault-irq");
if (led->pdata->led_fault_irq < 0)
dev_dbg(&led->pdev->dev, "led-fault-irq not used\n");
return 0;
}
@ -1033,6 +1291,49 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
}
}
/* setup irqs */
if (led->pdata->all_ramp_up_done_irq >= 0) {
rc = devm_request_threaded_irq(&led->pdev->dev,
led->pdata->all_ramp_up_done_irq,
NULL, qpnp_flash_led_irq_handler,
IRQF_ONESHOT,
"qpnp_flash_led_all_ramp_up_done_irq", led);
if (rc < 0) {
dev_err(&pdev->dev,
"Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n",
led->pdata->all_ramp_up_done_irq, rc);
return rc;
}
}
if (led->pdata->all_ramp_down_done_irq >= 0) {
rc = devm_request_threaded_irq(&led->pdev->dev,
led->pdata->all_ramp_down_done_irq,
NULL, qpnp_flash_led_irq_handler,
IRQF_ONESHOT,
"qpnp_flash_led_all_ramp_down_done_irq", led);
if (rc < 0) {
dev_err(&pdev->dev,
"Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n",
led->pdata->all_ramp_down_done_irq, rc);
return rc;
}
}
if (led->pdata->led_fault_irq >= 0) {
rc = devm_request_threaded_irq(&led->pdev->dev,
led->pdata->led_fault_irq,
NULL, qpnp_flash_led_irq_handler,
IRQF_ONESHOT,
"qpnp_flash_led_fault_irq", led);
if (rc < 0) {
dev_err(&pdev->dev,
"Unable to request led_fault(%d) IRQ(err:%d)\n",
led->pdata->led_fault_irq, rc);
return rc;
}
}
rc = qpnp_flash_led_init_settings(led);
if (rc < 0) {
dev_err(&pdev->dev,

View file

@ -26,11 +26,12 @@
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <linux/power_supply.h>
#include <linux/leds-qpnp-flash.h>
#include <linux/qpnp/qpnp-adc.h>
#include <linux/qpnp/qpnp-revid.h>
#include "leds.h"
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include "leds.h"
#define FLASH_LED_PERIPHERAL_SUBTYPE(base) (base + 0x05)
#define FLASH_SAFETY_TIMER(base) (base + 0x40)
@ -1154,6 +1155,47 @@ error_regulator_enable:
return rc;
}
int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
{
struct led_classdev *led_cdev = trigger_to_lcdev(trig);
struct flash_node_data *flash_node;
struct qpnp_flash_led *led;
int rc, val = 0;
if (!led_cdev) {
pr_err("Invalid led_trigger provided\n");
return -EINVAL;
}
flash_node = container_of(led_cdev, struct flash_node_data, cdev);
led = dev_get_drvdata(&flash_node->pdev->dev);
if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) {
dev_err(&led->pdev->dev, "Invalid options %d\n", options);
return -EINVAL;
}
if (options & ENABLE_REGULATOR) {
rc = flash_regulator_enable(led, flash_node, true);
if (rc < 0) {
dev_err(&led->pdev->dev,
"enable regulator failed, rc=%d\n", rc);
return rc;
}
}
if (options & QUERY_MAX_CURRENT) {
val = qpnp_flash_led_get_max_avail_current(flash_node, led);
if (val < 0) {
dev_err(&led->pdev->dev,
"query max current failed, rc=%d\n", val);
return val;
}
}
return val;
}
static void qpnp_flash_led_work(struct work_struct *work)
{
struct flash_node_data *flash_node = container_of(work,

View file

@ -44,6 +44,22 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
return led_cdev->brightness;
}
static inline struct led_classdev *trigger_to_lcdev(struct led_trigger *trig)
{
struct led_classdev *led_cdev;
read_lock(&trig->leddev_list_lock);
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
if (!strcmp(led_cdev->default_trigger, trig->name)) {
read_unlock(&trig->leddev_list_lock);
return led_cdev;
}
}
read_unlock(&trig->leddev_list_lock);
return NULL;
}
void led_init_core(struct led_classdev *led_cdev);
void led_stop_software_blink(struct led_classdev *led_cdev);

View file

@ -14,11 +14,21 @@
#define __LEDS_QPNP_FLASH_V2_H
#include <linux/leds.h>
#include "leds.h"
#include <linux/notifier.h>
#define ENABLE_REGULATOR BIT(0)
#define QUERY_MAX_CURRENT BIT(1)
enum flash_led_irq_type {
LED_FAULT_IRQ = BIT(0),
MITIGATION_IRQ = BIT(1),
FLASH_TIMER_EXP_IRQ = BIT(2),
ALL_RAMP_DOWN_DONE_IRQ = BIT(3),
ALL_RAMP_UP_DONE_IRQ = BIT(4),
LED3_RAMP_UP_DONE_IRQ = BIT(5),
LED2_RAMP_UP_DONE_IRQ = BIT(6),
LED1_RAMP_UP_DONE_IRQ = BIT(7),
INVALID_IRQ = BIT(8),
};
int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options);
int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb);
int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb);
#endif

View file

@ -0,0 +1,23 @@
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LEDS_QPNP_FLASH_H
#define __LEDS_QPNP_FLASH_H
#include <linux/leds.h>
#define ENABLE_REGULATOR BIT(0)
#define QUERY_MAX_CURRENT BIT(1)
int qpnp_flash_led_prepare(struct led_trigger *trig, int options);
#endif