diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 1102cb5d4f6f..7b06a6bd896a 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -13,6 +13,8 @@ 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. @@ -93,6 +95,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>; diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 786ffa822851..86f4c4cd4d2a 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -16,13 +16,16 @@ #include #include #include +#include #include #include #include #include +#include #include #include +#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) @@ -40,6 +43,7 @@ #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_MOD_CTRL_MASK BIT(7) #define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2) @@ -125,9 +129,11 @@ struct flash_switch_data { * Flash LED configuration read from device tree */ struct flash_led_platform_data { - u8 isc_delay_us; - u8 hw_strobe_option; - bool hdrm_auto_mode_en; + int all_ramp_up_done_irq; + int all_ramp_down_done_irq; + u8 isc_delay_us; + u8 hw_strobe_option; + bool hdrm_auto_mode_en; }; /* @@ -146,20 +152,37 @@ 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) + u8 val) { int rc; 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", - addr, rc); + 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", - val, addr); + dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%04X\n", + val, addr); return rc; } @@ -521,6 +544,34 @@ 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 status; + + 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), &status); + if (rc < 0) { + dev_err(&led->pdev->dev, "Failed to read interrupt status reg, rc=%d\n", + rc); + return IRQ_HANDLED; + } + + 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; + + dev_dbg(&led->pdev->dev, "irq handled, irq_type=%x, irq_status=%x\n", + irq_type, status); + return IRQ_HANDLED; +} + static int qpnp_flash_led_regulator_setup(struct qpnp_flash_led *led, struct flash_switch_data *snode, bool on) { @@ -923,6 +974,16 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, 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"); + return 0; } @@ -1033,6 +1094,35 @@ 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; + } + } + rc = qpnp_flash_led_init_settings(led); if (rc < 0) { dev_err(&pdev->dev, diff --git a/include/linux/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h index 47fd0699a9c1..823b6e6646c3 100644 --- a/include/linux/leds-qpnp-flash-v2.h +++ b/include/linux/leds-qpnp-flash-v2.h @@ -19,6 +19,18 @@ #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); #endif