[PATCH V5 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5
Currently, for WLED5, the FSC (Full scale current) setting is not updated properly due to driver toggling the wrong register after an FSC update. On WLED5 we should only toggle the MOD_SYNC bit after a brightness update. For an FSC update we need to toggle the SYNC bits instead. Fix it by adopting the common wled3_sync_toggle() for WLED5 and introducing new code to the brightness update path to compensate. Signed-off-by: Kiran Gunda Reviewed-by: Daniel Thompson --- drivers/video/backlight/qcom-wled.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index fc8b443..e9fbe24 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -348,7 +348,7 @@ static int wled3_sync_toggle(struct wled *wled) return rc; } -static int wled5_sync_toggle(struct wled *wled) +static int wled5_mod_sync_toggle(struct wled *wled) { int rc; u8 val; @@ -445,10 +445,23 @@ static int wled_update_status(struct backlight_device *bl) goto unlock_mutex; } - rc = wled->wled_sync_toggle(wled); - if (rc < 0) { - dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - goto unlock_mutex; + if (wled->version < 5) { + rc = wled->wled_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled sync failed rc:%d\n", rc); + goto unlock_mutex; + } + } else { + /* +* For WLED5 toggling the MOD_SYNC_BIT updates the +* brightness +*/ + rc = wled5_mod_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled mod sync failed rc:%d\n", + rc); + goto unlock_mutex; + } } } @@ -1459,7 +1472,7 @@ static int wled_configure(struct wled *wled) size = ARRAY_SIZE(wled5_opts); *cfg = wled5_config_defaults; wled->wled_set_brightness = wled5_set_brightness; - wled->wled_sync_toggle = wled5_sync_toggle; + wled->wled_sync_toggle = wled3_sync_toggle; wled->wled_cabc_config = wled5_cabc_config; wled->wled_ovp_delay = wled5_ovp_delay; wled->wled_auto_detection_required = -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 0/2] Fix WLED FSC Sync and brightness Sync settings
This patch series has the following two WLED fixes 1. As per the current implementation, for WLED5, after the FSC (Full Scale Current) update the driver is incorrectly toggling the MOD_SYNC register instead of toggling the SYNC register. The patch 1/2 fixes this by toggling the SYNC register after FSC update. 2. Currently, the sync bits are set-then-cleared after FSC and brightness update. As per hardware team recommendation the FSC and brightness sync takes place from clear-then-set transition of the sync bits. The patch 2/2 fies this issue. changes from V4: 1. Rebased this patch series on the below patch. "backlight-qcom-wled-Use-sink_addr-for-sync-toggle.patch". Changes from V3: 1. Updated the patch description as per Daneil's suggestion. 2. Added Daniel's "Reviewed-by" tag for patch 2/2. 3. Updated the cover letter to use "set" and "clear" properly. Changes from V2: 1. Added Daniel's "Reviewed-by" tag for patch 1/2. 2. Updated the patch 2/2 description with "set" and "clear" terminology instead of "1" and "0". 3. Updated the cover letter with "set" and "clear" terminology instead of "1" and "0". Changes from V1: 1. Updated the cover letter. 2. Updated the description of the patches as per Daniel's suggestion. Kiran Gunda (2): backlight: qcom-wled: Fix FSC update issue for WLED5 backlight: qcom-wled: Correct the sync_toggle sequence drivers/video/backlight/qcom-wled.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 2/2] backlight: qcom-wled: Correct the sync_toggle sequence
As per the current implementation, after FSC (Full Scale Current) and brightness update the sync bits are set-then-cleared. But, the FSC and brightness sync takes place when the sync bits are set (e.g. on a rising edge). So the hardware team recommends a clear-then-set approach in order to guarantee such a transition regardless of the previous register state. Signed-off-by: Kiran Gunda Reviewed-by: Daniel Thompson --- drivers/video/backlight/qcom-wled.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index e9fbe24..7c02f87 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -337,13 +337,13 @@ static int wled3_sync_toggle(struct wled *wled) rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED3_SINK_REG_SYNC, - mask, mask); + mask, WLED3_SINK_REG_SYNC_CLEAR); if (rc < 0) return rc; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED3_SINK_REG_SYNC, - mask, WLED3_SINK_REG_SYNC_CLEAR); + mask, mask); return rc; } @@ -353,17 +353,17 @@ static int wled5_mod_sync_toggle(struct wled *wled) int rc; u8 val; - val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : -WLED5_SINK_REG_SYNC_MOD_B_BIT; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, val); + WLED5_SINK_REG_SYNC_MASK, 0); if (rc < 0) return rc; + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : +WLED5_SINK_REG_SYNC_MOD_B_BIT; return regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, 0); + WLED5_SINK_REG_SYNC_MASK, val); } static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 2/2] backlight: qcom-wled: Correct the sync_toggle sequence
As per the current implementation, after FSC (Full Scale Current) and brightness update the sync bits are set-then-cleared. But, the FSC and brightness sync takes place when the sync bits are set (e.g. on a rising edge). So the hardware team recommends a clear-then-set approach in order to guarantee such a transition regardless of the previous register state. Signed-off-by: Kiran Gunda Reviewed-by: Daniel Thompson --- drivers/video/backlight/qcom-wled.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index aef52b9..19f83ac 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -337,13 +337,13 @@ static int wled3_sync_toggle(struct wled *wled) rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, mask); + mask, WLED3_SINK_REG_SYNC_CLEAR); if (rc < 0) return rc; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, WLED3_SINK_REG_SYNC_CLEAR); + mask, mask); return rc; } @@ -353,17 +353,17 @@ static int wled5_mod_sync_toggle(struct wled *wled) int rc; u8 val; - val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : -WLED5_SINK_REG_SYNC_MOD_B_BIT; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, val); + WLED5_SINK_REG_SYNC_MASK, 0); if (rc < 0) return rc; + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : +WLED5_SINK_REG_SYNC_MOD_B_BIT; return regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, 0); + WLED5_SINK_REG_SYNC_MASK, val); } static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5
Currently, for WLED5, the FSC (Full scale current) setting is not updated properly due to driver toggling the wrong register after an FSC update. On WLED5 we should only toggle the MOD_SYNC bit after a brightness update. For an FSC update we need to toggle the SYNC bits instead. Fix it by adopting the common wled3_sync_toggle() for WLED5 and introducing new code to the brightness update path to compensate. Signed-off-by: Kiran Gunda Reviewed-by: Daniel Thompson --- drivers/video/backlight/qcom-wled.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 3bc7800..aef52b9 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -348,7 +348,7 @@ static int wled3_sync_toggle(struct wled *wled) return rc; } -static int wled5_sync_toggle(struct wled *wled) +static int wled5_mod_sync_toggle(struct wled *wled) { int rc; u8 val; @@ -445,10 +445,23 @@ static int wled_update_status(struct backlight_device *bl) goto unlock_mutex; } - rc = wled->wled_sync_toggle(wled); - if (rc < 0) { - dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - goto unlock_mutex; + if (wled->version < 5) { + rc = wled->wled_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled sync failed rc:%d\n", rc); + goto unlock_mutex; + } + } else { + /* +* For WLED5 toggling the MOD_SYNC_BIT updates the +* brightness +*/ + rc = wled5_mod_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled mod sync failed rc:%d\n", + rc); + goto unlock_mutex; + } } } @@ -1459,7 +1472,7 @@ static int wled_configure(struct wled *wled) size = ARRAY_SIZE(wled5_opts); *cfg = wled5_config_defaults; wled->wled_set_brightness = wled5_set_brightness; - wled->wled_sync_toggle = wled5_sync_toggle; + wled->wled_sync_toggle = wled3_sync_toggle; wled->wled_cabc_config = wled5_cabc_config; wled->wled_ovp_delay = wled5_ovp_delay; wled->wled_auto_detection_required = -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 0/2] Fix WLED FSC Sync and brightness Sync settings
This patch series has the following two WLED fixes 1. As per the current implementation, for WLED5, after the FSC (Full Scale Current) update the driver is incorrectly toggling the MOD_SYNC register instead of toggling the SYNC register. The patch 1/2 fixes this by toggling the SYNC register after FSC update. 2. Currently, the sync bits are set-then-cleared after FSC and brightness update. As per hardware team recommendation the FSC and brightness sync takes place from clear-then-set transition of the sync bits. The patch 2/2 fies this issue. Changes from V3: 1. Updated the patch description as per Daneil's suggestion. 2. Added Daniel's "Reviewed-by" tag for patch 2/2. 3. Updated the cover letter to use "set" and "clear" properly. Changes from V2: 1. Added Daniel's "Reviewed-by" tag for patch 1/2. 2. Updated the patch 2/2 description with "set" and "clear" terminology instead of "1" and "0". 3. Updated the cover letter with "set" and "clear" terminology instead of "1" and "0". Changes from V1: 1. Updated the cover letter. 2. Updated the description of the patches as per Daniel's suggestion. Kiran Gunda (2): backlight: qcom-wled: Fix FSC update issue for WLED5 backlight: qcom-wled: Correct the sync_toggle sequence drivers/video/backlight/qcom-wled.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 2/2] backlight: qcom-wled: Correct the sync_toggle sequence
As per the current implementation, after FSC (Full Scale Current) and brightness update the sync bits are transitioned from set-then-clear. But, the FSC and brightness sync takes place during a clear-then-set transition of the sync bits. So the hardware team recommends a clear-then-set approach in order to guarantee such a transition regardless of the previous register state. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index aef52b9..19f83ac 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -337,13 +337,13 @@ static int wled3_sync_toggle(struct wled *wled) rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, mask); + mask, WLED3_SINK_REG_SYNC_CLEAR); if (rc < 0) return rc; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, WLED3_SINK_REG_SYNC_CLEAR); + mask, mask); return rc; } @@ -353,17 +353,17 @@ static int wled5_mod_sync_toggle(struct wled *wled) int rc; u8 val; - val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : -WLED5_SINK_REG_SYNC_MOD_B_BIT; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, val); + WLED5_SINK_REG_SYNC_MASK, 0); if (rc < 0) return rc; + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : +WLED5_SINK_REG_SYNC_MOD_B_BIT; return regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, 0); + WLED5_SINK_REG_SYNC_MASK, val); } static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 0/2] Fix WLED FSC Sync and brightness Sync settings
This patch series has the following two WLED fixes 1. As per the current implementation, for WLED5, after the FSC (Full Scale Current) update the driver is incorrectly toggling the MOD_SYNC register instead of toggling the SYNC register. The patch 1/2 fixes this by toggling the SYNC register after FSC update. 2. Currently, the sync bits are transitioned from set-then-clear after FSC and brightness update. As per hardware team recommendation the FSC and brightness sync takes place from clear-then-set transition of the sync bits. The patch 2/2 fies this issue. Changes from V2: 1. Added Daniel's "Reviewed-by" tag for patch 1/2. 2. Updated the patch 2/2 description with "set" and "clear" terminology instead of "1" and "0". 3. Updated the cover letter with "set" and "clear" terminology instead of "1" and "0". Changes from V1: 1. Updated the cover letter. 2. Updated the description of the patches as per Daniel's suggestion. Kiran Gunda (2): backlight: qcom-wled: Fix FSC update issue for WLED5 backlight: qcom-wled: Correct the sync_toggle sequence drivers/video/backlight/qcom-wled.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5
Currently, for WLED5, the FSC (Full scale current) setting is not updated properly due to driver toggling the wrong register after an FSC update. On WLED5 we should only toggle the MOD_SYNC bit after a brightness update. For an FSC update we need to toggle the SYNC bits instead. Fix it by adopting the common wled3_sync_toggle() for WLED5 and introducing new code to the brightness update path to compensate. Signed-off-by: Kiran Gunda Reviewed-by: Daniel Thompson --- drivers/video/backlight/qcom-wled.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 3bc7800..aef52b9 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -348,7 +348,7 @@ static int wled3_sync_toggle(struct wled *wled) return rc; } -static int wled5_sync_toggle(struct wled *wled) +static int wled5_mod_sync_toggle(struct wled *wled) { int rc; u8 val; @@ -445,10 +445,23 @@ static int wled_update_status(struct backlight_device *bl) goto unlock_mutex; } - rc = wled->wled_sync_toggle(wled); - if (rc < 0) { - dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - goto unlock_mutex; + if (wled->version < 5) { + rc = wled->wled_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled sync failed rc:%d\n", rc); + goto unlock_mutex; + } + } else { + /* +* For WLED5 toggling the MOD_SYNC_BIT updates the +* brightness +*/ + rc = wled5_mod_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled mod sync failed rc:%d\n", + rc); + goto unlock_mutex; + } } } @@ -1459,7 +1472,7 @@ static int wled_configure(struct wled *wled) size = ARRAY_SIZE(wled5_opts); *cfg = wled5_config_defaults; wled->wled_set_brightness = wled5_set_brightness; - wled->wled_sync_toggle = wled5_sync_toggle; + wled->wled_sync_toggle = wled3_sync_toggle; wled->wled_cabc_config = wled5_cabc_config; wled->wled_ovp_delay = wled5_ovp_delay; wled->wled_auto_detection_required = -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5
Currently, for WLED5, the FSC (Full scale current) setting is not updated properly due to driver toggling the wrong register after an FSC update. On WLED5 we should only toggle the MOD_SYNC bit after a brightness update. For an FSC update we need to toggle the SYNC bits instead. Fix it by adopting the common wled3_sync_toggle() for WLED5 and introducing new code to the brightness update path to compensate. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 3bc7800..aef52b9 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -348,7 +348,7 @@ static int wled3_sync_toggle(struct wled *wled) return rc; } -static int wled5_sync_toggle(struct wled *wled) +static int wled5_mod_sync_toggle(struct wled *wled) { int rc; u8 val; @@ -445,10 +445,23 @@ static int wled_update_status(struct backlight_device *bl) goto unlock_mutex; } - rc = wled->wled_sync_toggle(wled); - if (rc < 0) { - dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - goto unlock_mutex; + if (wled->version < 5) { + rc = wled->wled_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled sync failed rc:%d\n", rc); + goto unlock_mutex; + } + } else { + /* +* For WLED5 toggling the MOD_SYNC_BIT updates the +* brightness +*/ + rc = wled5_mod_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled mod sync failed rc:%d\n", + rc); + goto unlock_mutex; + } } } @@ -1459,7 +1472,7 @@ static int wled_configure(struct wled *wled) size = ARRAY_SIZE(wled5_opts); *cfg = wled5_config_defaults; wled->wled_set_brightness = wled5_set_brightness; - wled->wled_sync_toggle = wled5_sync_toggle; + wled->wled_sync_toggle = wled3_sync_toggle; wled->wled_cabc_config = wled5_cabc_config; wled->wled_ovp_delay = wled5_ovp_delay; wled->wled_auto_detection_required = -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 0/2] Fix WLED FSC Sync and brightness Sync settings
This patch series has the following two WLED fixes 1. As per the current implementation, for WLED5, after the FSC (Full Scale Current) update the driver is incorrectly toggling the MOD_SYNC register instead of toggling the SYNC register. The patch 1/2 fixes this by toggling the SYNC register after FSC update. 2. Currently, the sync bits are transitioned from 1 to 0 after FSC and brightness update. As per hardware team recommendation the FSC and brightness sync takes place from 0 to 1 transition. The patch 2/2 fies this issue. Changes from V1: 1. Updated the cover letter. 2. Updated the description of the patches as per Daniel's suggestion. Kiran Gunda (2): backlight: qcom-wled: Fix FSC update issue for WLED5 backlight: qcom-wled: Correct the sync_toggle sequence drivers/video/backlight/qcom-wled.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 2/2] backlight: qcom-wled: Correct the sync_toggle sequence
As per the current implementation, after FSC (Full Scale Current) and brightness update the sync bits are transitioned from 1 to 0. But, the FSC and brightness sync takes place during a 0 to 1 transition of the sync bits. So the hardware team recommends a clear-then-set approach in order to guarantee such a transition regardless of the previous register state. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index aef52b9..19f83ac 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -337,13 +337,13 @@ static int wled3_sync_toggle(struct wled *wled) rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, mask); + mask, WLED3_SINK_REG_SYNC_CLEAR); if (rc < 0) return rc; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, WLED3_SINK_REG_SYNC_CLEAR); + mask, mask); return rc; } @@ -353,17 +353,17 @@ static int wled5_mod_sync_toggle(struct wled *wled) int rc; u8 val; - val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : -WLED5_SINK_REG_SYNC_MOD_B_BIT; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, val); + WLED5_SINK_REG_SYNC_MASK, 0); if (rc < 0) return rc; + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : +WLED5_SINK_REG_SYNC_MOD_B_BIT; return regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, 0); + WLED5_SINK_REG_SYNC_MASK, val); } static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5
Currently, for WLED5, after FSC register update MOD_SYNC_BIT is toggled instead of SYNC_BIT. MOD_SYNC_BIT has to be toggled after the brightness update and SYNC_BIT has to be toggled after FSC update for WLED5. Fix it. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 3bc7800..aef52b9 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -348,7 +348,7 @@ static int wled3_sync_toggle(struct wled *wled) return rc; } -static int wled5_sync_toggle(struct wled *wled) +static int wled5_mod_sync_toggle(struct wled *wled) { int rc; u8 val; @@ -445,10 +445,23 @@ static int wled_update_status(struct backlight_device *bl) goto unlock_mutex; } - rc = wled->wled_sync_toggle(wled); - if (rc < 0) { - dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - goto unlock_mutex; + if (wled->version < 5) { + rc = wled->wled_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled sync failed rc:%d\n", rc); + goto unlock_mutex; + } + } else { + /* +* For WLED5 toggling the MOD_SYNC_BIT updates the +* brightness +*/ + rc = wled5_mod_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled mod sync failed rc:%d\n", + rc); + goto unlock_mutex; + } } } @@ -1459,7 +1472,7 @@ static int wled_configure(struct wled *wled) size = ARRAY_SIZE(wled5_opts); *cfg = wled5_config_defaults; wled->wled_set_brightness = wled5_set_brightness; - wled->wled_sync_toggle = wled5_sync_toggle; + wled->wled_sync_toggle = wled3_sync_toggle; wled->wled_cabc_config = wled5_cabc_config; wled->wled_ovp_delay = wled5_ovp_delay; wled->wled_auto_detection_required = -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 2/2] backlight: qcom-wled: Correct the sync_toggle sequence
Currently the FSC SYNC_BIT and MOD_SYNC_BIT are toggled from 1 to 0 to update the FSC and brightenss settings. Change this sequence form 0 to 1 as per the hardware team recommendation to update the FSC and brightness correctly. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index aef52b9..19f83ac 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -337,13 +337,13 @@ static int wled3_sync_toggle(struct wled *wled) rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, mask); + mask, WLED3_SINK_REG_SYNC_CLEAR); if (rc < 0) return rc; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, WLED3_SINK_REG_SYNC_CLEAR); + mask, mask); return rc; } @@ -353,17 +353,17 @@ static int wled5_mod_sync_toggle(struct wled *wled) int rc; u8 val; - val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : -WLED5_SINK_REG_SYNC_MOD_B_BIT; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, val); + WLED5_SINK_REG_SYNC_MASK, 0); if (rc < 0) return rc; + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : +WLED5_SINK_REG_SYNC_MOD_B_BIT; return regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, 0); + WLED5_SINK_REG_SYNC_MASK, val); } static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 0/2] Fix WLED FSC Sync and brightness Sync settings
The FSC (Full scale current) setting is not updated properly due to the wrong register toggling for WLED5. Also the ILED_SYNC toggle and MOD_SYNC toggle sequence is updated as per the hardware team recommendation to fix the FSC update and brightness update issue. Kiran Gunda (2): backlight: qcom-wled: Fix FSC update issue for WLED5 backlight: qcom-wled: Correct the sync_toggle sequence drivers/video/backlight/qcom-wled.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5
Currently, for WLED5, after FSC register update MOD_SYNC_BIT is toggled instead of SYNC_BIT. MOD_SYNC_BIT has to be toggled after the brightness update and SYNC_BIT has to be toggled after FSC update for WLED5. Fix it. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 3bc7800..aef52b9 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -348,7 +348,7 @@ static int wled3_sync_toggle(struct wled *wled) return rc; } -static int wled5_sync_toggle(struct wled *wled) +static int wled5_mod_sync_toggle(struct wled *wled) { int rc; u8 val; @@ -445,10 +445,23 @@ static int wled_update_status(struct backlight_device *bl) goto unlock_mutex; } - rc = wled->wled_sync_toggle(wled); - if (rc < 0) { - dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - goto unlock_mutex; + if (wled->version < 5) { + rc = wled->wled_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled sync failed rc:%d\n", rc); + goto unlock_mutex; + } + } else { + /* +* For WLED5 toggling the MOD_SYNC_BIT updates the +* brightness +*/ + rc = wled5_mod_sync_toggle(wled); + if (rc < 0) { + dev_err(wled->dev, "wled mod sync failed rc:%d\n", + rc); + goto unlock_mutex; + } } } @@ -1459,7 +1472,7 @@ static int wled_configure(struct wled *wled) size = ARRAY_SIZE(wled5_opts); *cfg = wled5_config_defaults; wled->wled_set_brightness = wled5_set_brightness; - wled->wled_sync_toggle = wled5_sync_toggle; + wled->wled_sync_toggle = wled3_sync_toggle; wled->wled_cabc_config = wled5_cabc_config; wled->wled_ovp_delay = wled5_ovp_delay; wled->wled_auto_detection_required = -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 0/2] Fix WLED FSC Sync and brightness Sync settings
The FSC (Full scale current) setting is not updated properly due to the wrong register toggling for WLED5. Also the ILED_SYNC toggle and MOD_SYNC toggle sequence is updated as per the hardware team recommendation to fix the FSC update and brightness update issue. Kiran Gunda (2): backlight: qcom-wled: Fix FSC update issue for WLED5 backlight: qcom-wled: Correct the sync_toggle sequence drivers/video/backlight/qcom-wled.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 2/2] backlight: qcom-wled: Correct the sync_toggle sequence
Currently the FSC SYNC_BIT and MOD_SYNC_BIT are toggled from 1 to 0 to update the FSC and brightenss settings. Change this sequence form 0 to 1 as per the hardware team recommendation to update the FSC and brightness correctly. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index aef52b9..19f83ac 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -337,13 +337,13 @@ static int wled3_sync_toggle(struct wled *wled) rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, mask); + mask, WLED3_SINK_REG_SYNC_CLEAR); if (rc < 0) return rc; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_SINK_REG_SYNC, - mask, WLED3_SINK_REG_SYNC_CLEAR); + mask, mask); return rc; } @@ -353,17 +353,17 @@ static int wled5_mod_sync_toggle(struct wled *wled) int rc; u8 val; - val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : -WLED5_SINK_REG_SYNC_MOD_B_BIT; rc = regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, val); + WLED5_SINK_REG_SYNC_MASK, 0); if (rc < 0) return rc; + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : +WLED5_SINK_REG_SYNC_MOD_B_BIT; return regmap_update_bits(wled->regmap, wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, - WLED5_SINK_REG_SYNC_MASK, 0); + WLED5_SINK_REG_SYNC_MASK, val); } static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 1/2] mfd: qcom-spmi-pmic: Convert bindings to .yaml format
Convert the bindings from .txt to .yaml format. Signed-off-by: Kiran Gunda --- .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 80 -- .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml| 117 + 2 files changed, 117 insertions(+), 80 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt create mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt deleted file mode 100644 index 79367a4..000 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt +++ /dev/null @@ -1,80 +0,0 @@ - Qualcomm SPMI PMICs multi-function device bindings - -The Qualcomm SPMI series presently includes PM8941, PM8841 and PMA8084 -PMICs. These PMICs use a QPNP scheme through SPMI interface. -QPNP is effectively a partitioning scheme for dividing the SPMI extended -register space up into logical pieces, and set of fixed register -locations/definitions within these regions, with some of these regions -specifically used for interrupt handling. - -The QPNP PMICs are used with the Qualcomm Snapdragon series SoCs, and are -interfaced to the chip via the SPMI (System Power Management Interface) bus. -Support for multiple independent functions are implemented by splitting the -16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes -each. A function can consume one or more of these fixed-size register regions. - -Required properties: -- compatible: Should contain one of: - "qcom,pm8941", - "qcom,pm8841", - "qcom,pma8084", - "qcom,pm8019", - "qcom,pm8226", - "qcom,pm8110", - "qcom,pma8084", - "qcom,pmi8962", - "qcom,pmd9635", - "qcom,pm8994", - "qcom,pmi8994", - "qcom,pm8916", - "qcom,pm8004", - "qcom,pm8909", - "qcom,pm8950", - "qcom,pmi8950", - "qcom,pm8998", - "qcom,pmi8998", - "qcom,pm8005", - or generalized "qcom,spmi-pmic". -- reg: Specifies the SPMI USID slave address for this device. - For more information see: - Documentation/devicetree/bindings/spmi/spmi.yaml - -Required properties for peripheral child nodes: -- compatible: Should contain "qcom,xxx", where "xxx" is a peripheral name. - -Optional properties for peripheral child nodes: -- interrupts: Interrupts are specified as a 4-tuple. For more information - see: - Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt -- interrupt-names: Corresponding interrupt name to the interrupts property - -Each child node of SPMI slave id represents a function of the PMIC. In the -example below the rtc device node represents a peripheral of pm8941 -SID = 0. The regulator device node represents a peripheral of pm8941 SID = 1. - -Example: - - spmi { - compatible = "qcom,spmi-pmic-arb"; - - pm8941@0 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - - rtc { - compatible = "qcom,rtc"; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "alarm"; - }; - }; - - pm8941@1 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x1 SPMI_USID>; - - regulator { - compatible = "qcom,regulator"; - regulator-name = "8941_boost"; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml new file mode 100644 index 000..b753bdb --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/qcom,spmi-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SPMI PMICs multi-function device bindings + +maintainers: + - Stephen Boyd + - Kiran Gunda + +descript
[PATCH V5 2/2] mfd: qcom-spmi-pmic: Add support for pm6150 and pm6150l
Add the compatibles and PMIC ids for pm6150 and pm6150l PMICs found on SC7180 based platforms. Signed-off-by: Kiran Gunda Acked-for-MFD-by: Lee Jones Reviewed-by: Stephen Boyd --- Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 2 ++ drivers/mfd/qcom-spmi-pmic.c | 4 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index b753bdb..151953a 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -59,6 +59,8 @@ patternProperties: - qcom,pm8005 - qcom,pm660l - qcom,pm660 + - qcom,pm6150l + - qcom,pm6150 - enum: - qcom,spmi-pmic diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index a35d5cf..78e9084 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -38,6 +38,8 @@ #define PM8005_SUBTYPE 0x18 #define PM660L_SUBTYPE 0x1A #define PM660_SUBTYPE 0x1B +#define PM6150L_SUBTYPE0x1F +#define PM6150_SUBTYPE 0x28 static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, @@ -61,6 +63,8 @@ static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,pm8005",.data = (void *)PM8005_SUBTYPE }, { .compatible = "qcom,pm660l",.data = (void *)PM660L_SUBTYPE }, { .compatible = "qcom,pm660", .data = (void *)PM660_SUBTYPE }, + { .compatible = "qcom,pm6150l",.data = (void *)PM6150L_SUBTYPE }, + { .compatible = "qcom,pm6150", .data = (void *)PM6150_SUBTYPE }, { } }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 0/2] Convert qcom,spmi-pmic bindings from .txt to .yaml
This patch series does the following: - converts the qcom,spmi-pmic bindings from .txt to .yaml format - Sorted the compatible strings - Adds PM6150 and PM6150L subtypes. Changes from V1: - Sorted the compatible strings as per Stephen Boyd's comments. - Added a patch to convert the qcom,spmi-pmic from .txt to .yaml format. Changes from V2: - Addressed Stephen Boyd and Rob Herring comments. Changes from V3: - Fixed compilation error in .yaml file. Changes from V4: - Addressed Stephen Boyd comments on .yaml conversion patch - Added "Reviewed-by" tag from Stephen Boyd - Added "Acked-for-MFD-by" tag from Lee Jones Kiran Gunda (2): mfd: qcom-spmi-pmic: Convert bindings to .yaml format mfd: qcom-spmi-pmic: Add support for pm6150 and pm6150l .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 80 -- .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml| 119 + drivers/mfd/qcom-spmi-pmic.c | 4 + 3 files changed, 123 insertions(+), 80 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt create mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 1/2] mfd: qcom-spmi-pmic: Convert bindings to .yaml format
Convert the bindings from .txt to .yaml format. Signed-off-by: Kiran Gunda --- .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 80 - .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml| 127 + 2 files changed, 127 insertions(+), 80 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt create mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt deleted file mode 100644 index 79367a4..000 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt +++ /dev/null @@ -1,80 +0,0 @@ - Qualcomm SPMI PMICs multi-function device bindings - -The Qualcomm SPMI series presently includes PM8941, PM8841 and PMA8084 -PMICs. These PMICs use a QPNP scheme through SPMI interface. -QPNP is effectively a partitioning scheme for dividing the SPMI extended -register space up into logical pieces, and set of fixed register -locations/definitions within these regions, with some of these regions -specifically used for interrupt handling. - -The QPNP PMICs are used with the Qualcomm Snapdragon series SoCs, and are -interfaced to the chip via the SPMI (System Power Management Interface) bus. -Support for multiple independent functions are implemented by splitting the -16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes -each. A function can consume one or more of these fixed-size register regions. - -Required properties: -- compatible: Should contain one of: - "qcom,pm8941", - "qcom,pm8841", - "qcom,pma8084", - "qcom,pm8019", - "qcom,pm8226", - "qcom,pm8110", - "qcom,pma8084", - "qcom,pmi8962", - "qcom,pmd9635", - "qcom,pm8994", - "qcom,pmi8994", - "qcom,pm8916", - "qcom,pm8004", - "qcom,pm8909", - "qcom,pm8950", - "qcom,pmi8950", - "qcom,pm8998", - "qcom,pmi8998", - "qcom,pm8005", - or generalized "qcom,spmi-pmic". -- reg: Specifies the SPMI USID slave address for this device. - For more information see: - Documentation/devicetree/bindings/spmi/spmi.yaml - -Required properties for peripheral child nodes: -- compatible: Should contain "qcom,xxx", where "xxx" is a peripheral name. - -Optional properties for peripheral child nodes: -- interrupts: Interrupts are specified as a 4-tuple. For more information - see: - Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt -- interrupt-names: Corresponding interrupt name to the interrupts property - -Each child node of SPMI slave id represents a function of the PMIC. In the -example below the rtc device node represents a peripheral of pm8941 -SID = 0. The regulator device node represents a peripheral of pm8941 SID = 1. - -Example: - - spmi { - compatible = "qcom,spmi-pmic-arb"; - - pm8941@0 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - - rtc { - compatible = "qcom,rtc"; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "alarm"; - }; - }; - - pm8941@1 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x1 SPMI_USID>; - - regulator { - compatible = "qcom,regulator"; - regulator-name = "8941_boost"; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml new file mode 100644 index 000..e458dd1 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/qcom,spmi-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SPMI PMICs multi-function device bindings + +maintainers: + - Stephen Boyd + +description: | + The Qualcomm SPMI PMICs
[PATCH V4 2/2] mfd: qcom-spmi-pmic: Add support for pm6150 and pm6150l
Add the compatibles and PMIC ids for pm6150 and pm6150l PMICs found on SC7180 based platforms. Signed-off-by: Kiran Gunda --- Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 2 ++ drivers/mfd/qcom-spmi-pmic.c | 4 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index e458dd1..2acddbc 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -58,6 +58,8 @@ patternProperties: - qcom,pm8005 - qcom,pm660l - qcom,pm660 + - qcom,pm6150l + - qcom,pm6150 - enum: - qcom,spmi-pmic diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index a35d5cf..78e9084 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -38,6 +38,8 @@ #define PM8005_SUBTYPE 0x18 #define PM660L_SUBTYPE 0x1A #define PM660_SUBTYPE 0x1B +#define PM6150L_SUBTYPE0x1F +#define PM6150_SUBTYPE 0x28 static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, @@ -61,6 +63,8 @@ static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,pm8005",.data = (void *)PM8005_SUBTYPE }, { .compatible = "qcom,pm660l",.data = (void *)PM660L_SUBTYPE }, { .compatible = "qcom,pm660", .data = (void *)PM660_SUBTYPE }, + { .compatible = "qcom,pm6150l",.data = (void *)PM6150L_SUBTYPE }, + { .compatible = "qcom,pm6150", .data = (void *)PM6150_SUBTYPE }, { } }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 0/2] Convert qcom,spmi-pmic bindings from .txt to .yaml
This patch series does the following: - converts the qcom,spmi-pmic bindings from .txt to .yaml format - Sorted the compatible strings - Adds PM6150 and PM6150L subtypes. Changes from V3: - Fixed compilation error in .yaml file. Changes from V2: - Addressed Stephen Boyd and Rob Herring comments. Kiran Gunda (2): mfd: qcom-spmi-pmic: Convert bindings to .yaml format mfd: qcom-spmi-pmic: Add support for pm6150 and pm6150l .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 80 - .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml| 129 + drivers/mfd/qcom-spmi-pmic.c | 4 + 3 files changed, 133 insertions(+), 80 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt create mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 0/2] Convert qcom,spmi-pmic bindings from .txt to .yaml
This patch series does the following: 1. converts the qcom,spmi-pmic bindings from .txt to .yaml format 2. Sorted the compatible strings 3. Adds PM6150 and PM6150L subtypes. Changes from V2: - Addressed Stephen Boyd and Rob Herring comments. Kiran Gunda (2): mfd: qcom-spmi-pmic: Convert bindings to .yaml format mfd: qcom-spmi-pmic: Add support for pm6150 and pm6150l .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 80 - .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml| 129 + drivers/mfd/qcom-spmi-pmic.c | 4 + 3 files changed, 133 insertions(+), 80 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt create mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 2/2] mfd: qcom-spmi-pmic: Add support for pm6150 and pm6150l
Add the compatibles and PMIC ids for pm6150 and pm6150l PMICs found on SC7180 based platforms. Signed-off-by: Kiran Gunda --- Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 2 ++ drivers/mfd/qcom-spmi-pmic.c | 4 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index 0b3e440..92cf7e9 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -58,6 +58,8 @@ patternProperties: - qcom,pm8005 - qcom,pm660l - qcom,pm660 + - qcom,pm6150l + - qcom,pm6150 - enum: - qcom,spmi-pmic diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index a35d5cf..6d8b688 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -38,6 +38,8 @@ #define PM8005_SUBTYPE 0x18 #define PM660L_SUBTYPE 0x1A #define PM660_SUBTYPE 0x1B +#define PM6150L_SUBTYPE0x1F +#define PM6150_SUBTYPE 0x28 static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, @@ -61,6 +63,8 @@ static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,pm8005",.data = (void *)PM8005_SUBTYPE }, { .compatible = "qcom,pm660l",.data = (void *)PM660L_SUBTYPE }, { .compatible = "qcom,pm660", .data = (void *)PM660_SUBTYPE }, + { .compatible = "qcom,pm6150l", .data = (void *)PM6150L_SUBTYPE }, + { .compatible = "qcom,pm6150",.data = (void *)PM6150_SUBTYPE }, { } }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 1/2] mfd: qcom-spmi-pmic: Convert bindings to .yaml format
Convert the bindings from .txt to .yaml format. Signed-off-by: Kiran Gunda --- .../devicetree/bindings/mfd/qcom,spmi-pmic.txt | 80 - .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml| 127 + 2 files changed, 127 insertions(+), 80 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt create mode 100644 Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt deleted file mode 100644 index 79367a4..000 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt +++ /dev/null @@ -1,80 +0,0 @@ - Qualcomm SPMI PMICs multi-function device bindings - -The Qualcomm SPMI series presently includes PM8941, PM8841 and PMA8084 -PMICs. These PMICs use a QPNP scheme through SPMI interface. -QPNP is effectively a partitioning scheme for dividing the SPMI extended -register space up into logical pieces, and set of fixed register -locations/definitions within these regions, with some of these regions -specifically used for interrupt handling. - -The QPNP PMICs are used with the Qualcomm Snapdragon series SoCs, and are -interfaced to the chip via the SPMI (System Power Management Interface) bus. -Support for multiple independent functions are implemented by splitting the -16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes -each. A function can consume one or more of these fixed-size register regions. - -Required properties: -- compatible: Should contain one of: - "qcom,pm8941", - "qcom,pm8841", - "qcom,pma8084", - "qcom,pm8019", - "qcom,pm8226", - "qcom,pm8110", - "qcom,pma8084", - "qcom,pmi8962", - "qcom,pmd9635", - "qcom,pm8994", - "qcom,pmi8994", - "qcom,pm8916", - "qcom,pm8004", - "qcom,pm8909", - "qcom,pm8950", - "qcom,pmi8950", - "qcom,pm8998", - "qcom,pmi8998", - "qcom,pm8005", - or generalized "qcom,spmi-pmic". -- reg: Specifies the SPMI USID slave address for this device. - For more information see: - Documentation/devicetree/bindings/spmi/spmi.yaml - -Required properties for peripheral child nodes: -- compatible: Should contain "qcom,xxx", where "xxx" is a peripheral name. - -Optional properties for peripheral child nodes: -- interrupts: Interrupts are specified as a 4-tuple. For more information - see: - Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt -- interrupt-names: Corresponding interrupt name to the interrupts property - -Each child node of SPMI slave id represents a function of the PMIC. In the -example below the rtc device node represents a peripheral of pm8941 -SID = 0. The regulator device node represents a peripheral of pm8941 SID = 1. - -Example: - - spmi { - compatible = "qcom,spmi-pmic-arb"; - - pm8941@0 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - - rtc { - compatible = "qcom,rtc"; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "alarm"; - }; - }; - - pm8941@1 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x1 SPMI_USID>; - - regulator { - compatible = "qcom,regulator"; - regulator-name = "8941_boost"; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml new file mode 100644 index 000..0b3e440 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/qcom,spmi-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SPMI PMICs multi-function device bindings + +maintainers: + - Stephen Boyd + +description: | + The Qualcomm SPMI PMICs
[PATCH V9 6/6] backlight: qcom-wled: Add auto string detection logic
The auto string detection algorithm checks if the current WLED sink configuration is valid. It tries enabling every sink and checks if the OVP fault is observed. Based on this information it detects and enables the valid sink configuration. Auto calibration will be triggered when the OVP fault interrupts are seen frequently thereby it tries to fix the sink configuration. The auto-detection also kicks in when the connected LED string of the display-backlight malfunctions (because of damage) and requires the damaged string to be turned off to prevent the complete panel and/or board from being damaged. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 400 +++- 1 file changed, 394 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 658b1e0..33b6007 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -17,19 +17,29 @@ #define WLED_MAX_STRINGS 4 #define WLED_DEFAULT_BRIGHTNESS2048 - +#define WLED_SOFT_START_DLY_US 1 #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF /* WLED3/WLED4 control registers */ +#define WLED3_CTRL_REG_FAULT_STATUS0x08 +#define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0) +#define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1) +#define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) + +#define WLED3_CTRL_REG_INT_RT_STS 0x10 +#define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1) + #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) #define WLED3_CTRL_REG_MOD_EN_SHIFT 7 +#define WLED3_CTRL_REG_FEEDBACK_CONTROL0x48 + #define WLED3_CTRL_REG_FREQ0x4c #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0) #define WLED3_CTRL_REG_OVP 0x4d -#define WLED3_CTRL_REG_OVP_MASK GENMASK(1, 0) +#define WLED3_CTRL_REG_OVP_MASK GENMASK(1, 0) #define WLED3_CTRL_REG_ILIMIT 0x4e #define WLED3_CTRL_REG_ILIMIT_MASKGENMASK(2, 0) @@ -119,6 +129,7 @@ struct wled_config { bool ext_gen; bool cabc; bool external_pfet; + bool auto_detection_enabled; }; struct wled { @@ -127,17 +138,22 @@ struct wled { struct regmap *regmap; struct mutex lock; /* Lock to avoid race from thread irq handler */ ktime_t last_short_event; + ktime_t start_ovp_fault_time; u16 ctrl_addr; u16 sink_addr; u16 max_string_count; + u16 auto_detection_ovp_count; u32 brightness; u32 max_brightness; u32 short_count; + u32 auto_detect_count; bool disabled_by_short; bool has_short_detect; int short_irq; + int ovp_irq; struct wled_config cfg; + struct delayed_work ovp_work; int (*wled_set_brightness)(struct wled *wled, u16 brightness); }; @@ -182,6 +198,13 @@ static int wled4_set_brightness(struct wled *wled, u16 brightness) return 0; } +static void wled_ovp_work(struct work_struct *work) +{ + struct wled *wled = container_of(work, +struct wled, ovp_work.work); + enable_irq(wled->ovp_irq); +} + static int wled_module_enable(struct wled *wled, int val) { int rc; @@ -193,7 +216,25 @@ static int wled_module_enable(struct wled *wled, int val) WLED3_CTRL_REG_MOD_EN, WLED3_CTRL_REG_MOD_EN_MASK, val << WLED3_CTRL_REG_MOD_EN_SHIFT); - return rc; + if (rc < 0) + return rc; + + if (wled->ovp_irq > 0) { + if (val) { + /* +* The hardware generates a storm of spurious OVP +* interrupts during soft start operations. So defer +* enabling the IRQ for 10ms to ensure that the +* soft start is complete. +*/ + schedule_delayed_work(&wled->ovp_work, HZ / 100); + } else { + if (!cancel_delayed_work_sync(&wled->ovp_work)) + disable_irq(wled->ovp_irq); + } + } + + return 0; } static int wled_sync_toggle(struct wled *wled) @@ -300,6 +341,304 @@ static irqreturn_t wled_short_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +#define AUTO_DETECT_BRIGHTNESS 200 + +static void wled_auto_string_detection(struct wled *wled) +{ + int rc
[PATCH V7 4/6] backlight: qcom-wled: Add support for WLED4 peripheral.
WLED4 peripheral is present on some PMICs like pmi8998 and pm660l. It has a different register map and configurations are also different. Add support for it. Signed-off-by: Kiran Gunda Reviewed-by: Bjorn Andersson --- drivers/video/backlight/qcom-wled.c | 263 +++- 1 file changed, 257 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 45eeda4..2807b4b 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -17,7 +17,7 @@ #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF -/* WLED3 control registers */ +/* WLED3/WLED4 control registers */ #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) #define WLED3_CTRL_REG_MOD_EN_SHIFT 7 @@ -31,7 +31,7 @@ #define WLED3_CTRL_REG_ILIMIT 0x4e #define WLED3_CTRL_REG_ILIMIT_MASKGENMASK(2, 0) -/* WLED3 sink registers */ +/* WLED3/WLED4 sink registers */ #define WLED3_SINK_REG_SYNC0x47 #define WLED3_SINK_REG_SYNC_CLEAR 0x00 @@ -56,6 +56,28 @@ #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10)) #define WLED3_SINK_REG_STR_CABC_MASK BIT(7) +/* WLED4 specific sink registers */ +#define WLED4_SINK_REG_CURR_SINK 0x46 +#define WLED4_SINK_REG_CURR_SINK_MASK GENMASK(7, 4) +#define WLED4_SINK_REG_CURR_SINK_SHFT 4 + +/* WLED4 specific per-'string' registers below */ +#define WLED4_SINK_REG_STR_MOD_EN(n) (0x50 + (n * 0x10)) +#define WLED4_SINK_REG_STR_MOD_MASK BIT(7) + +#define WLED4_SINK_REG_STR_FULL_SCALE_CURR(n) (0x52 + (n * 0x10)) +#define WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK GENMASK(3, 0) + +#define WLED4_SINK_REG_STR_MOD_SRC(n) (0x53 + (n * 0x10)) +#define WLED4_SINK_REG_STR_MOD_SRC_MASK BIT(0) +#define WLED4_SINK_REG_STR_MOD_SRC_INT0x00 +#define WLED4_SINK_REG_STR_MOD_SRC_EXT0x01 + +#define WLED4_SINK_REG_STR_CABC(n) (0x56 + (n * 0x10)) +#define WLED4_SINK_REG_STR_CABC_MASK BIT(7) + +#define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10)) + struct wled_var_cfg { const u32 *values; u32 (*fn)(u32); @@ -90,6 +112,7 @@ struct wled { struct device *dev; struct regmap *regmap; u16 ctrl_addr; + u16 sink_addr; u16 max_string_count; u32 brightness; u32 max_brightness; @@ -116,6 +139,29 @@ static int wled3_set_brightness(struct wled *wled, u16 brightness) return 0; } +static int wled4_set_brightness(struct wled *wled, u16 brightness) +{ + int rc, i; + u16 low_limit = wled->max_brightness * 4 / 1000; + u8 v[2]; + + /* WLED4's lower limit of operation is 0.4% */ + if (brightness > 0 && brightness < low_limit) + brightness = low_limit; + + v[0] = brightness & 0xff; + v[1] = (brightness >> 8) & 0xf; + + for (i = 0; i < wled->cfg.num_strings; ++i) { + rc = regmap_bulk_write(wled->regmap, wled->sink_addr + + WLED4_SINK_REG_BRIGHT(i), v, 2); + if (rc < 0) + return rc; + } + + return 0; +} + static int wled_module_enable(struct wled *wled, int val) { int rc; @@ -267,6 +313,120 @@ static int wled3_setup(struct wled *wled) .enabled_strings = {0, 1, 2, 3}, }; +static int wled4_setup(struct wled *wled) +{ + int rc, temp, i, j; + u16 addr; + u8 sink_en = 0; + u32 sink_cfg = 0; + + rc = regmap_update_bits(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_OVP, + WLED3_CTRL_REG_OVP_MASK, wled->cfg.ovp); + if (rc < 0) + return rc; + + rc = regmap_update_bits(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, + WLED3_CTRL_REG_ILIMIT_MASK, + wled->cfg.boost_i_limit); + if (rc < 0) + return rc; + + rc = regmap_update_bits(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_FREQ, + WLED3_CTRL_REG_FREQ_MASK, + wled->cfg.switch_freq); + if (rc < 0) + return rc; + + rc = regmap_read(wled->regmap, wled->sink_addr + +WLED4_SINK_REG_CURR_SINK, &sink_cfg); + if (rc < 0) + return rc; + + for (i = 0
[PATCH V1] dt-bindings: pinctrl: qcom-pmic-gpio: Add support for pm6150/pm6150l
Add support for the PM6150 and PM6150L GPIO support to the Qualcomm PMIC GPIO binding. Signed-off-by: Kiran Gunda --- Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt | 4 drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt index c32bf32..2f48cca 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt @@ -23,6 +23,8 @@ PMIC's from Qualcomm. "qcom,pms405-gpio" "qcom,pm8150-gpio" "qcom,pm8150b-gpio" + "qcom,pm6150-gpio" + "qcom,pm6150l-gpio" And must contain either "qcom,spmi-gpio" or "qcom,ssbi-gpio" if the device is on an spmi bus or an ssbi bus respectively @@ -100,6 +102,8 @@ to specify in a pin configuration subnode: and gpio8) gpio1-gpio12 for pm8150b (holes on gpio3, gpio4, gpio7) gpio1-gpio12 for pm8150l (hole on gpio7) + gpio1-gpio10 for pm6150 + gpio1-gpio12 for pm6150l - function: Usage: required diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index f1fece5..387917c 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1121,6 +1121,8 @@ static int pmic_gpio_remove(struct platform_device *pdev) { .compatible = "qcom,pm8150b-gpio", .data = (void *) 12 }, /* pm8150l has 12 GPIOs with holes on 7 */ { .compatible = "qcom,pm8150l-gpio", .data = (void *) 12 }, + { .compatible = "qcom,pm6150-gpio", .data = (void *) 10 }, + { .compatible = "qcom,pm6150l-gpio", .data = (void *) 12 }, { }, }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 1/2] ARM: dts: qcom: pm6150: Add PM6150/PM6150L PMIC peripherals
Add PM6150/PM6150L peripherals such as PON, GPIOs, ADC and other PMIC infra modules. Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/pm6150.dtsi | 85 +++ arch/arm64/boot/dts/qcom/pm6150l.dtsi | 47 +++ 2 files changed, 132 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pm6150.dtsi create mode 100644 arch/arm64/boot/dts/qcom/pm6150l.dtsi diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi new file mode 100644 index 000..22d2445 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, The Linux Foundation. All rights reserved. + +#include +#include +#include +#include +#include + +&spmi_bus { + pm6150_lsid0: pmic@0 { + compatible = "qcom,pm6150", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm6150_pon: pon@800 { + compatible = "qcom,pm8998-pon"; + reg = <0x800>; + mode-bootloader = <0x2>; + mode-recovery = <0x1>; + + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + }; + + pm6150_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + io-channels = <&pm6150_adc ADC5_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pm6150_adc: adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + adc-chan@ADC5_DIE_TEMP { + reg = ; + label = "die_temp"; + }; + }; + + pm6150_gpio: gpios@c000 { + compatible = "qcom,pm6150-gpio", "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <0 0xc0 0 IRQ_TYPE_NONE>, +<0 0xc1 0 IRQ_TYPE_NONE>, +<0 0xc2 0 IRQ_TYPE_NONE>, +<0 0xc3 0 IRQ_TYPE_NONE>, +<0 0xc4 0 IRQ_TYPE_NONE>, +<0 0xc5 0 IRQ_TYPE_NONE>, +<0 0xc6 0 IRQ_TYPE_NONE>, +<0 0xc7 0 IRQ_TYPE_NONE>, +<0 0xc8 0 IRQ_TYPE_NONE>, +<0 0xc9 0 IRQ_TYPE_NONE>; + + interrupt-names = "pm6150_gpio1", "pm6150_gpio2", + "pm6150_gpio3", "pm6150_gpio4", + "pm6150_gpio5", "pm6150_gpio6", + "pm6150_gpio7", "pm6150_gpio8", + "pm6150_gpio9", "pm6150_gpio10"; + }; + }; + + pm6150_lsid1: pmic@1 { + compatible = "qcom,pm6150", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi new file mode 100644 index 000..a262092 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, The Linux Foundation. All rights reserved. + +#include +#include + +&spmi_bus { + pm6150l_lsid4: pmic@4 { + compatible = "qcom,pm6150l", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>
[PATCH V2 2/2] ARM: dts: qcom: sc7180-regulator: Add RPMh regulators for SC7180
Add regulator devices for SC7180 as RPMh regulators. This ensures that consumers are able to modify the physical state of PMIC regulators. Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi | 210 + 1 file changed, 210 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi diff --git a/arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi b/arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi new file mode 100644 index 000..50a675b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, The Linux Foundation. All rights reserved. + +#include + +&apps_rsc { + pm6150-rpmh-regulators { + compatible = "qcom,pm6150-rpmh-regulators"; + qcom,pmic-id = "a"; + + vreg_s1a_1p1: smps1 { + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + }; + + vreg_s4a_1p0: smps4 { + regulator-min-microvolt = <824000>; + regulator-max-microvolt = <112>; + }; + + vreg_s5a_2p0: smps5 { + regulator-min-microvolt = <1744000>; + regulator-max-microvolt = <204>; + }; + + vreg_l1a_1p2: ldo1 { + regulator-min-microvolt = <1178000>; + regulator-max-microvolt = <1256000>; + regulator-initial-mode = ; + }; + + vreg_l2a_1p0: ldo2 { + regulator-min-microvolt = <944000>; + regulator-max-microvolt = <1056000>; + regulator-initial-mode = ; + }; + + vreg_l3a_1p0: ldo3 { + regulator-min-microvolt = <968000>; + regulator-max-microvolt = <1064000>; + regulator-initial-mode = ; + }; + + vreg_l4a_0p8: ldo4 { + regulator-min-microvolt = <824000>; + regulator-max-microvolt = <928000>; + regulator-initial-mode = ; + }; + + vreg_l5a_2p7: ldo5 { + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <300>; + regulator-initial-mode = ; + }; + + vreg_l6a_0p6: ldo6 { + regulator-min-microvolt = <568000>; + regulator-max-microvolt = <648000>; + regulator-initial-mode = ; + }; + + vreg_l9a_0p6: ldo9 { + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <80>; + regulator-initial-mode = ; + }; + + vreg_l10a_1p8: ldo10 { + regulator-min-microvolt = <180>; + regulator-max-microvolt = <1832000>; + regulator-initial-mode = ; + }; + + vreg_l11a_1p8: ldo11 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + }; + + vreg_l12a_1p8: ldo12 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1952000>; + regulator-initial-mode = ; + }; + + vreg_l13a_1p8: ldo13 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + }; + + vreg_l14a_1p8: ldo14 { + regulator-min-microvolt = <1728000>; + regulator-max-microvolt = <1832000>; + regulator-initial-mode = ; + }; + + vreg_l15a_1p8: ldo15 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + }; + + vreg_l16a_2p7: ldo16 { + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + + vreg_l17a_3p0: ldo17 { + regulator-min-microvolt = <292&g
[PATCH V1 1/2] ARM: dts: qcom: pm6150: Add PM6150/PM6150L PMIC peripherals
Add PM6150/PM6150L peripherals such as PON, GPIOs, ADC and other PMIC infra modules. Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/pm6150.dtsi | 82 +++ arch/arm64/boot/dts/qcom/pm6150l.dtsi | 47 2 files changed, 129 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pm6150.dtsi create mode 100644 arch/arm64/boot/dts/qcom/pm6150l.dtsi diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi new file mode 100644 index 000..c2389866 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, The Linux Foundation. All rights reserved. + +#include +#include +#include +#include +#include + +&spmi_bus { + pm6150_lsid0: pmic@0 { + compatible = "qcom,pm6150", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm6150_pon: pon@800 { + compatible = "qcom,pm8998-pon"; + reg = <0x800>; + mode-bootloader = <0x2>; + mode-recovery = <0x1>; + + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + }; + + pm6150_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + io-channels = <&pm6150_adc ADC5_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pm6150_adc: adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + adc-chan@ADC5_DIE_TEMP { + reg = ; + label = "die_temp"; + }; + }; + + pm6150_gpio: gpios@c000 { + compatible = "qcom,pm6150-gpio", "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <0 0xc0 0 IRQ_TYPE_NONE>, +<0 0xc1 0 IRQ_TYPE_NONE>, +<0 0xc2 0 IRQ_TYPE_NONE>, +<0 0xc3 0 IRQ_TYPE_NONE>, +<0 0xc4 0 IRQ_TYPE_NONE>, +<0 0xc5 0 IRQ_TYPE_NONE>, +<0 0xc6 0 IRQ_TYPE_NONE>, +<0 0xc7 0 IRQ_TYPE_NONE>; + + interrupt-names = "pm6150_gpio1", "pm6150_gpio2", + "pm6150_gpio3", "pm6150_gpio4", + "pm6150_gpio5", "pm6150_gpio6", + "pm6150_gpio7", "pm6150_gpio8"; + }; + }; + + pm6150_lsid1: pmic@1 { + compatible = "qcom,pm6150", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi new file mode 100644 index 000..a262092 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, The Linux Foundation. All rights reserved. + +#include +#include + +&spmi_bus { + pm6150l_lsid4: pmic@4 { + compatible = "qcom,pm6150l", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm6150l_gpios: gpios@c000 { + compatible = "qcom,pm6150l-gpio", "qcom,spmi-gpio
[PATCH V1 2/2] ARM: dts: qcom: sc7180-regulator: Add RPMh regulators for SC7180
Add regulator devices for SC7180 as RPMh regulators. This ensures that consumers are able to modify the physical state of PMIC regulators. Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi | 210 + 1 file changed, 210 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi diff --git a/arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi b/arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi new file mode 100644 index 000..50a675b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-regulator.dtsi @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, The Linux Foundation. All rights reserved. + +#include + +&apps_rsc { + pm6150-rpmh-regulators { + compatible = "qcom,pm6150-rpmh-regulators"; + qcom,pmic-id = "a"; + + vreg_s1a_1p1: smps1 { + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + }; + + vreg_s4a_1p0: smps4 { + regulator-min-microvolt = <824000>; + regulator-max-microvolt = <112>; + }; + + vreg_s5a_2p0: smps5 { + regulator-min-microvolt = <1744000>; + regulator-max-microvolt = <204>; + }; + + vreg_l1a_1p2: ldo1 { + regulator-min-microvolt = <1178000>; + regulator-max-microvolt = <1256000>; + regulator-initial-mode = ; + }; + + vreg_l2a_1p0: ldo2 { + regulator-min-microvolt = <944000>; + regulator-max-microvolt = <1056000>; + regulator-initial-mode = ; + }; + + vreg_l3a_1p0: ldo3 { + regulator-min-microvolt = <968000>; + regulator-max-microvolt = <1064000>; + regulator-initial-mode = ; + }; + + vreg_l4a_0p8: ldo4 { + regulator-min-microvolt = <824000>; + regulator-max-microvolt = <928000>; + regulator-initial-mode = ; + }; + + vreg_l5a_2p7: ldo5 { + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <300>; + regulator-initial-mode = ; + }; + + vreg_l6a_0p6: ldo6 { + regulator-min-microvolt = <568000>; + regulator-max-microvolt = <648000>; + regulator-initial-mode = ; + }; + + vreg_l9a_0p6: ldo9 { + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <80>; + regulator-initial-mode = ; + }; + + vreg_l10a_1p8: ldo10 { + regulator-min-microvolt = <180>; + regulator-max-microvolt = <1832000>; + regulator-initial-mode = ; + }; + + vreg_l11a_1p8: ldo11 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + }; + + vreg_l12a_1p8: ldo12 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1952000>; + regulator-initial-mode = ; + }; + + vreg_l13a_1p8: ldo13 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + }; + + vreg_l14a_1p8: ldo14 { + regulator-min-microvolt = <1728000>; + regulator-max-microvolt = <1832000>; + regulator-initial-mode = ; + }; + + vreg_l15a_1p8: ldo15 { + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + regulator-initial-mode = ; + }; + + vreg_l16a_2p7: ldo16 { + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + + vreg_l17a_3p0: ldo17 { + regulator-min-microvolt = <292&g
[PATCH V1] regulator: qcom-rpmh: Fix PMIC5 BoB min voltage
Correct the PMIC5 BoB min voltage from 0.3V to 3V. Also correct the voltage selector accordingly. Signed-off-by: Kiran Gunda --- Depends-on: This patch depends on "Add regulator support for SC7180" drivers/regulator/qcom-rpmh-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 8ae7ddf..c86ad40 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -735,8 +735,8 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode) static const struct rpmh_vreg_hw_data pmic5_bob = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_bypass_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(30, 0, 135, 32000), - .n_voltages = 136, + .voltage_range = REGULATOR_LINEAR_RANGE(300, 0, 31, 32000), + .n_voltages = 32, .pmic_mode_map = pmic_mode_map_pmic5_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 2/2] regulator: qcom-rpmh: add PM6150/PM6150L regulator support
Add support for PM6150/PM6150L regulators. This ensures that consumers are able to modify the physical state of PMIC regulators. Signed-off-by: Kiran Gunda --- drivers/regulator/qcom-rpmh-regulator.c | 62 - 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index db6c085..8ae7ddf 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2018, The Linux Foundation. All rights reserved. +// Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -878,6 +878,58 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode) {}, }; +static const struct rpmh_vreg_init_data pm6150_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l7-l8"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l4-l7-l8"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l4-l7-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo_lv, "vdd-l10-l14-l15"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l12-l13"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l11-l12-l13"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo_lv, "vdd-l11-l12-l13"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l10-l14-l15"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l10-l14-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), + {}, +}; + +static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("bob","bob%s1", &pmic5_bob, "vdd-bob"), + {}, +}; + static int rpmh_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -940,6 +992,14 @@ static int rpmh_regulator_probe(struct platform_device *pdev) .compatible = "qcom,pmi8998-rpmh-regulators", .data = pmi8998_vreg_data, }, + { + .compatible = "qcom,pm6150-rpmh-regulators", + .data = pm6150_vreg_data, + }, + { + .compatible = "qcom,pm6150l-rpmh-regulators", + .data = pm6150l_vreg_data, + }, {} }; MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 1/2] regulator: dt-bindings: Add PM6150x compatibles
Add PM6150 and PM6150L compatibles for Qualcomm SC7180 platfrom. Signed-off-by: Kiran Gunda --- Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt index bab9f71..97c3e0b 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt @@ -28,6 +28,8 @@ Supported regulator node names: PM8150L:smps1 - smps8, ldo1 - ldo11, bob, flash, rgb PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 PMI8998:bob + PM6150: smps1 - smps5, ldo1 - ldo19 + PM6150L:smps1 - smps8, ldo1 - ldo11, bob First Level Nodes - PMIC @@ -43,6 +45,8 @@ First Level Nodes - PMIC "qcom,pm8150l-rpmh-regulators" "qcom,pm8998-rpmh-regulators" "qcom,pmi8998-rpmh-regulators" + "qcom,pm6150-rpmh-regulators" + "qcom,pm6150l-rpmh-regulators" - qcom,pmic-id Usage: required -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 3/8] backlight: qcom-wled: Add new properties for PMI8998
Update the bindings with the new properties used for PMI8998. Signed-off-by: Kiran Gunda Reviewed-by: Bjorn Andersson Reviewed-by: Rob Herring Acked-by: Daniel Thompson --- Changes from V3: - Removed the default values. - Removed pmi8998 example. Changes from V4: - modified qcom,enabled-strings property with decimal numbers. .../bindings/leds/backlight/qcom-wled.txt | 76 ++ 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt index 14f28f2..9d840d5 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt @@ -20,8 +20,7 @@ platforms. The PMIC is connected to the host processor via SPMI bus. - default-brightness Usage:optional Value type: - Definition: brightness value on boot, value from: 0-4095 - Default: 2048 + Definition: brightness value on boot, value from: 0-4095. - label Usage:required @@ -48,20 +47,24 @@ platforms. The PMIC is connected to the host processor via SPMI bus. - qcom,current-limit Usage:optional Value type: - Definition: mA; per-string current limit - value: For pm8941: from 0 to 25 with 5 mA step -Default 20 mA. -For pmi8998: from 0 to 30 with 5 mA step -Default 25 mA. + Definition: mA; per-string current limit; value from 0 to 25 with + 1 mA step. + This property is supported only for pm8941. + +- qcom,current-limit-microamp + Usage:optional + Value type: + Definition: uA; per-string current limit; value from 0 to 3 with + 2500 uA step. - qcom,current-boost-limit Usage:optional Value type: Definition: mA; boost current limit. For pm8941: one of: 105, 385, 525, 805, 980, 1260, 1400, - 1680. Default: 805 mA + 1680. For pmi8998: one of: 105, 280, 450, 620, 970, 1150, 1300, - 1500. Default: 970 mA + 1500. - qcom,switching-freq Usage:optional @@ -69,22 +72,66 @@ platforms. The PMIC is connected to the host processor via SPMI bus. Definition: kHz; switching frequency; one of: 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200, 4800, 9600. - Default: for pm8941: 1600 kHz - for pmi8998: 800 kHz - qcom,ovp Usage:optional Value type: Definition: V; Over-voltage protection limit; one of: - 27, 29, 32, 35. default: 29V + 27, 29, 32, 35. This property is supported only for PM8941. +- qcom,ovp-millivolt + Usage:optional + Value type: + Definition: mV; Over-voltage protection limit; + For pmi8998: one of 18100, 19600, 29600, 31100 + If this property is not specified for PM8941, it + falls back to "qcom,ovp" property. + - qcom,num-strings Usage:optional Value type: Definition: #; number of led strings attached; - value from 1 to 3. default: 2 - This property is supported only for PM8941. + value: For PM8941 from 1 to 3. +For PMI8998 from 1 to 4. + +- interrupts + Usage:optional + Value type: + Definition: Interrupts associated with WLED. This should be + "short" and "ovp" interrupts. Interrupts can be + specified as per the encoding listed under + Documentation/devicetree/bindings/spmi/ + qcom,spmi-pmic-arb.txt. + +- interrupt-names + Usage:optional + Value type: + Definition: Interrupt names associated with the interrupts. + Must be "short" and "ovp". The short circuit detection + is not supported for PM8941. + +- qcom,enabled-strings + Usage:optional + Value tyoe: + Definition: Array of the WLED strings numbered from 0 to 3. Each + string of leds are operated individually. Specify the + list of strings used by the device. Any combination of + led strings can be used. + +- qcom,external-pfet + Usage:optional + Value type: + Defini
[PATCH V5 2/8] backlight: qcom-wled: restructure the qcom-wled bindings
Restructure the qcom-wled bindings for the better readability. Signed-off-by: Kiran Gunda Reviewed-by: Bjorn Andersson Reviewed-by: Rob Herring Acked-by: Daniel Thompson --- Changes from V3: Added Reviewed-by and Acked-by tags. Changes from V4: None .../bindings/leds/backlight/qcom-wled.txt | 110 - 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt index fb39e32..14f28f2 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt @@ -1,30 +1,90 @@ Binding for Qualcomm Technologies, Inc. WLED driver -Required properties: -- compatible: should be "qcom,pm8941-wled" -- reg: slave address - -Optional properties: -- default-brightness: brightness value on boot, value from: 0-4095 - default: 2048 -- label: The name of the backlight device -- qcom,cs-out: bool; enable current sink output -- qcom,cabc: bool; enable content adaptive backlight control -- qcom,ext-gen: bool; use externally generated modulator signal to dim -- qcom,current-limit: mA; per-string current limit; value from 0 to 25 - default: 20mA -- qcom,current-boost-limit: mA; boost current limit; one of: - 105, 385, 525, 805, 980, 1260, 1400, 1680 - default: 805mA -- qcom,switching-freq: kHz; switching frequency; one of: - 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, - 1600, 1920, 2400, 3200, 4800, 9600, - default: 1600kHz -- qcom,ovp: V; Over-voltage protection limit; one of: - 27, 29, 32, 35 - default: 29V -- qcom,num-strings: #; number of led strings attached; value from 1 to 3 - default: 2 +WLED (White Light Emitting Diode) driver is used for controlling display +backlight that is part of PMIC on Qualcomm Technologies, Inc. reference +platforms. The PMIC is connected to the host processor via SPMI bus. + +- compatible + Usage:required + Value type: + Definition: should be one of: + "qcom,pm8941-wled" + "qcom,pmi8998-wled" + "qcom,pm660l-wled" + +- reg + Usage:required + Value type: + Definition: Base address of the WLED modules. + +- default-brightness + Usage:optional + Value type: + Definition: brightness value on boot, value from: 0-4095 + Default: 2048 + +- label + Usage:required + Value type: + Definition: The name of the backlight device + +- qcom,cs-out + Usage:optional + Value type: + Definition: enable current sink output. + This property is supported only for PM8941. + +- qcom,cabc + Usage:optional + Value type: + Definition: enable content adaptive backlight control. + +- qcom,ext-gen + Usage:optional + Value type: + Definition: use externally generated modulator signal to dim. + This property is supported only for PM8941. + +- qcom,current-limit + Usage:optional + Value type: + Definition: mA; per-string current limit + value: For pm8941: from 0 to 25 with 5 mA step +Default 20 mA. +For pmi8998: from 0 to 30 with 5 mA step +Default 25 mA. + +- qcom,current-boost-limit + Usage:optional + Value type: + Definition: mA; boost current limit. + For pm8941: one of: 105, 385, 525, 805, 980, 1260, 1400, + 1680. Default: 805 mA + For pmi8998: one of: 105, 280, 450, 620, 970, 1150, 1300, + 1500. Default: 970 mA + +- qcom,switching-freq + Usage:optional + Value type: +Definition: kHz; switching frequency; one of: 600, 640, 685, 738, + 800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200, + 4800, 9600. + Default: for pm8941: 1600 kHz + for pmi8998: 800 kHz + +- qcom,ovp + Usage:optional + Value type: + Definition: V; Over-voltage protection limit; one of: + 27, 29, 32, 35. default: 29V + This property is supported only for PM8941. + +- qcom,num-strings + Usage:optional + Value type: + Definition: #; number of led strings attached; + value from 1 to 3. default: 2 + This property is supported only for PM8941. Example: -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 7/8] backlight: qcom-wled: add support for short circuit handling
Handle the short circuit interrupt and check if the short circuit interrupt is valid. Re-enable the module to check if it goes away. Disable the module altogether if the short circuit event persists. Signed-off-by: Kiran Gunda Reviewed-by: Bjorn Andersson --- Changes from V3: - Added Reviewed by tag. - Addressed minor comments from Vinod Changes from V4: - Changed the return value from -EINVAL to -ENXIO - Re-initializing the short_count from 0 to 1. drivers/video/backlight/qcom-wled.c | 132 ++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 49fdd23..d891067 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +#include +#include +#include #include #include #include @@ -64,6 +67,16 @@ #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10)) #define WLED3_SINK_REG_STR_CABC_MASK BIT(7) +/* WLED4 specific control registers */ +#define WLED4_CTRL_REG_SHORT_PROTECT 0x5e +#define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7) + +#define WLED4_CTRL_REG_SEC_ACCESS 0xd0 +#define WLED4_CTRL_REG_SEC_UNLOCK 0xa5 + +#define WLED4_CTRL_REG_TEST1 0xe2 +#define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09 + /* WLED4 specific sink registers */ #define WLED4_SINK_REG_CURR_SINK 0x46 #define WLED4_SINK_REG_CURR_SINK_MASK GENMASK(7, 4) @@ -113,17 +126,23 @@ struct wled_config { bool cs_out_en; bool ext_gen; bool cabc; + bool external_pfet; }; struct wled { const char *name; struct device *dev; struct regmap *regmap; + struct mutex lock; /* Lock to avoid race from thread irq handler */ + ktime_t last_short_event; u16 ctrl_addr; u16 sink_addr; u16 max_string_count; u32 brightness; u32 max_brightness; + u32 short_count; + bool disabled_by_short; + bool has_short_detect; struct wled_config cfg; int (*wled_set_brightness)(struct wled *wled, u16 brightness); @@ -174,6 +193,9 @@ static int wled_module_enable(struct wled *wled, int val) { int rc; + if (wled->disabled_by_short) + return -ENXIO; + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_REG_MOD_EN, WLED_CTRL_REG_MOD_EN_MASK, @@ -210,18 +232,19 @@ static int wled_update_status(struct backlight_device *bl) bl->props.state & BL_CORE_FBBLANK) brightness = 0; + mutex_lock(&wled->lock); if (brightness) { rc = wled->wled_set_brightness(wled, brightness); if (rc < 0) { dev_err(wled->dev, "wled failed to set brightness rc:%d\n", rc); - return rc; + goto unlock_mutex; } rc = wled_sync_toggle(wled); if (rc < 0) { dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } @@ -229,15 +252,61 @@ static int wled_update_status(struct backlight_device *bl) rc = wled_module_enable(wled, !!brightness); if (rc < 0) { dev_err(wled->dev, "wled enable failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } wled->brightness = brightness; +unlock_mutex: + mutex_unlock(&wled->lock); + return rc; } +#define WLED_SHORT_DLY_MS 20 +#define WLED_SHORT_CNT_MAX 5 +#define WLED_SHORT_RESET_CNT_DLY_USUSEC_PER_SEC + +static irqreturn_t wled_short_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + s64 elapsed_time; + + wled->short_count++; + mutex_lock(&wled->lock); + rc = wled_module_enable(wled, false); + if (rc < 0) { + dev_err(wled->dev, "wled disable failed rc:%d\n", rc); + goto unlock_mutex; + } + + elapsed_time = ktime_us_delta(ktime_get(), + wled->last_short_event); + if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) + wled->short_count = 1; + + if (wled->short_count > WLED_SHORT_CNT_MAX) { + dev_err(wled->dev, "Short trig
[PATCH V2] thermal: qcom-spmi-temp-alarm: add support for GEN2 PMIC peripherals
From: David Collins Add support for the TEMP_ALARM GEN2 PMIC peripheral subtype. The GEN2 subtype defines an over temperature state with hysteresis instead of stage in the status register. There are two GEN2 states corresponding to stages 1 and 2. Signed-off-by: David Collins Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/thermal/qcom-spmi-temp-alarm.c | 92 ++ 1 file changed, 71 insertions(+), 21 deletions(-) Changes from [V1]: Rebased on top of 4.17-rc6 diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index 95f987d..ad4f3a8 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015, 2017, 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 @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -29,13 +30,17 @@ #define QPNP_TM_REG_ALARM_CTRL 0x46 #define QPNP_TM_TYPE 0x09 -#define QPNP_TM_SUBTYPE0x08 +#define QPNP_TM_SUBTYPE_GEN1 0x08 +#define QPNP_TM_SUBTYPE_GEN2 0x09 -#define STATUS_STAGE_MASK 0x03 +#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0) +#define STATUS_GEN2_STATE_MASK GENMASK(6, 4) +#define STATUS_GEN2_STATE_SHIFT4 -#define SHUTDOWN_CTRL1_THRESHOLD_MASK 0x03 +#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6) +#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0) -#define ALARM_CTRL_FORCE_ENABLE0x80 +#define ALARM_CTRL_FORCE_ENABLEBIT(7) /* * Trip point values based on threshold control @@ -58,6 +63,7 @@ struct qpnp_tm_chip { struct regmap *map; struct thermal_zone_device *tz_dev; + unsigned intsubtype; longtemp; unsigned intthresh; unsigned intstage; @@ -66,6 +72,9 @@ struct qpnp_tm_chip { struct iio_channel *adc; }; +/* This array maps from GEN2 alarm state to GEN1 alarm stage */ +static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3}; + static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data) { unsigned int val; @@ -84,30 +93,59 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data) return regmap_write(chip->map, chip->base + addr, data); } +/** + * qpnp_tm_get_temp_stage() - return over-temperature stage + * @chip: Pointer to the qpnp_tm chip + * + * Return: stage (GEN1) or state (GEN2) on success, or errno on failure. + */ +static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip) +{ + int ret; + u8 reg = 0; + + ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + if (ret < 0) + return ret; + + if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) + ret = reg & STATUS_GEN1_STAGE_MASK; + else + ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT; + + return ret; +} + /* * This function updates the internal temp value based on the * current thermal stage and threshold as well as the previous stage */ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) { - unsigned int stage; + unsigned int stage, stage_new, stage_old; int ret; - u8 reg = 0; - ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) return ret; + stage = ret; - stage = reg & STATUS_STAGE_MASK; + if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) { + stage_new = stage; + stage_old = chip->stage; + } else { + stage_new = alarm_state_map[stage]; + stage_old = alarm_state_map[chip->stage]; + } - if (stage > chip->stage) { + if (stage_new > stage_old) { /* increasing stage, use lower bound */ - chip->temp = (stage - 1) * TEMP_STAGE_STEP + + chip->temp = (stage_new - 1) * TEMP_STAGE_STEP + chip->thresh * TEMP_THRESH_STEP + TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; - } else if (stage < chip->stage) { + } else if (stage_new < stage_old) { /* decreasing stage, use upper bound */ - chip->temp = stage * TEMP_STAGE_STEP + + chip->temp = stage_new * TEMP_STAGE_STEP + chip->
[PATCH V2 4/5] backlight: qcom-wled: Add support for OVP interrupt handling
WLED peripheral has over voltage protection(OVP) circuitry and the OVP fault is notified through an interrupt. Though this fault condition rising is due to an incorrect hardware configuration is mitigated in the hardware, it still needs to be detected and handled. Add support for it. When WLED module is enabled, keep OVP fault interrupt disabled for 10 ms to account for soft start delay. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 118 +++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 2cfba77..80ae084 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -23,14 +23,20 @@ /* From DT binding */ #define WLED_DEFAULT_BRIGHTNESS2048 - +#define WLED_SOFT_START_DLY_US 1 #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF /* WLED3 Control registers */ #define WLED3_CTRL_REG_FAULT_STATUS0x08 +#define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0) +#define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1) +#define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) + +#define WLED3_CTRL_REG_INT_RT_STS 0x10 #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) +#define WLED3_CTRL_REG_MOD_EN_BIT BIT(7) #define WLED3_CTRL_REG_FREQ0x4c #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0) @@ -161,9 +167,12 @@ struct wled { u32 short_count; const int *version; int short_irq; + int ovp_irq; bool force_mod_disable; + bool ovp_irq_disabled; struct wled_config cfg; + struct delayed_work ovp_work; int (*wled_set_brightness)(struct wled *wled, u16 brightness); int (*wled_sync_toggle)(struct wled *wled); }; @@ -209,6 +218,32 @@ static int wled4_set_brightness(struct wled *wled, u16 brightness) return 0; } +static void wled_ovp_work(struct work_struct *work) +{ + u32 val; + int rc; + + struct wled *wled = container_of(work, +struct wled, ovp_work.work); + + rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, +&val); + if (rc < 0) + return; + + if (val & WLED3_CTRL_REG_MOD_EN_BIT) { + if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) { + enable_irq(wled->ovp_irq); + wled->ovp_irq_disabled = false; + } + } else { + if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) { + disable_irq(wled->ovp_irq); + wled->ovp_irq_disabled = true; + } + } +} + static int wled_module_enable(struct wled *wled, int val) { int rc; @@ -220,7 +255,12 @@ static int wled_module_enable(struct wled *wled, int val) WLED3_CTRL_REG_MOD_EN, WLED3_CTRL_REG_MOD_EN_MASK, WLED3_CTRL_REG_MOD_EN_MASK); - return rc; + if (rc < 0) + return rc; + + schedule_delayed_work(&wled->ovp_work, WLED_SOFT_START_DLY_US); + + return 0; } static int wled3_sync_toggle(struct wled *wled) @@ -346,6 +386,36 @@ static irqreturn_t wled_short_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + u32 int_sts, fault_sts; + + rc = regmap_read(wled->regmap, +wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, &int_sts); + if (rc < 0) { + dev_err(wled->dev, "Error in reading WLED3_INT_RT_STS rc=%d\n", + rc); + return IRQ_HANDLED; + } + + rc = regmap_read(wled->regmap, wled->ctrl_addr + +WLED3_CTRL_REG_FAULT_STATUS, &fault_sts); + if (rc < 0) { + dev_err(wled->dev, "Error in reading WLED_FAULT_STATUS rc=%d\n", + rc); + return IRQ_HANDLED; + } + + if (fault_sts & + (WLED3_CTRL_REG_OVP_FAULT_BIT | WLED3_CTRL_REG_ILIM_FAULT_BIT)) + dev_dbg(wled->dev, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n", + int_sts, fault_sts); + + return IRQ_HANDLED; +} + static int wled3_setup(struct wled *wled) { u16 addr; @@ -821,6 +891,44 @@ static int wled_configure_short_irq(struct wled *wled, return
[PATCH V2 5/5] backlight: qcom-wled: Add auto string detection logic
The auto string detection algorithm checks if the current WLED sink configuration is valid. It tries enabling every sink and checks if the OVP fault is observed. Based on this information it detects and enables the valid sink configuration. Auto calibration will be triggered when the OVP fault interrupts are seen frequently thereby it tries to fix the sink configuration. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 302 1 file changed, 302 insertions(+) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 80ae084..bacdf3f 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -33,11 +33,14 @@ #define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) #define WLED3_CTRL_REG_INT_RT_STS 0x10 +#define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1) #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) #define WLED3_CTRL_REG_MOD_EN_BIT BIT(7) +#define WLED3_CTRL_REG_FEEDBACK_CONTROL0x48 + #define WLED3_CTRL_REG_FREQ0x4c #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0) @@ -152,6 +155,7 @@ struct wled_config { bool ext_gen; bool cabc; bool external_pfet; + bool auto_detection_enabled; }; struct wled { @@ -160,8 +164,10 @@ struct wled { struct regmap *regmap; struct mutex lock; /* Lock to avoid race from ISR */ ktime_t last_short_event; + ktime_t start_ovp_fault_time; u16 ctrl_addr; u16 sink_addr; + u16 auto_detection_ovp_count; u32 brightness; u32 max_brightness; u32 short_count; @@ -170,6 +176,7 @@ struct wled { int ovp_irq; bool force_mod_disable; bool ovp_irq_disabled; + bool auto_detection_done; struct wled_config cfg; struct delayed_work ovp_work; @@ -386,6 +393,292 @@ static irqreturn_t wled_short_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +#define AUTO_DETECT_BRIGHTNESS 200 +static int wled_auto_string_detection(struct wled *wled) +{ + int rc = 0, i; + u32 sink_config = 0, int_sts; + u8 sink_test = 0, sink_valid = 0, val; + + if (wled->auto_detection_done) + return 0; + + /* read configured sink configuration */ + rc = regmap_read(wled->regmap, wled->sink_addr + +WLED4_SINK_REG_CURR_SINK, &sink_config); + if (rc < 0) { + pr_err("Failed to read SINK configuration rc=%d\n", rc); + goto failed_detect; + } + + /* disable the module before starting detection */ + rc = regmap_update_bits(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, + WLED3_CTRL_REG_MOD_EN_MASK, 0); + if (rc < 0) { + pr_err("Failed to disable WLED module rc=%d\n", rc); + goto failed_detect; + } + + /* set low brightness across all sinks */ + rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS); + if (rc < 0) { + pr_err("Failed to set brightness for auto detection rc=%d\n", + rc); + goto failed_detect; + } + + if (wled->cfg.cabc) { + for (i = 0; i < wled->cfg.num_strings; i++) { + rc = regmap_update_bits(wled->regmap, wled->sink_addr + + WLED4_SINK_REG_STR_CABC(i), + WLED4_SINK_REG_STR_CABC_MASK, + 0); + if (rc < 0) + goto failed_detect; + } + } + + /* disable all sinks */ + rc = regmap_write(wled->regmap, + wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0); + if (rc < 0) { + pr_err("Failed to disable all sinks rc=%d\n", rc); + goto failed_detect; + } + + /* iterate through the strings one by one */ + for (i = 0; i < wled->cfg.num_strings; i++) { + sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i)); + + /* Enable feedback control */ + rc = regmap_write(wled->regmap, wled->ctrl_addr + + WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1); + if (rc < 0) { + pr_err("Failed to enable feedback for SINK %d rc = %d\n", + i + 1, rc); + goto failed_detect; +
[PATCH V2 3/5] backlight: qcom-wled: Add support for short circuit handling
Handle the short circuit interrupt and check if the short circuit interrupt is valid. Re-enable the module to check if it goes away. Disable the module altogether if the short circuit event persists. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 134 ++-- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index be8b8d3..2cfba77 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +#include +#include +#include #include #include #include @@ -23,7 +26,9 @@ #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF -/* Control registers */ +/* WLED3 Control registers */ +#define WLED3_CTRL_REG_FAULT_STATUS0x08 + #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) @@ -36,7 +41,17 @@ #define WLED3_CTRL_REG_ILIMIT 0x4e #define WLED3_CTRL_REG_ILIMIT_MASKGENMASK(2, 0) -/* sink registers */ +/* WLED4 control registers */ +#define WLED4_CTRL_REG_SHORT_PROTECT 0x5e +#define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7) + +#define WLED4_CTRL_REG_SEC_ACCESS 0xd0 +#define WLED4_CTRL_REG_SEC_UNLOCK 0xa5 + +#define WLED4_CTRL_REG_TEST1 0xe2 +#define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09 + +/* WLED3 sink registers */ #define WLED3_SINK_REG_SYNC0x47 #define WLED3_SINK_REG_SYNC_MASK GENMASK(2, 0) #define WLED4_SINK_REG_SYNC_MASK GENMASK(3, 0) @@ -130,17 +145,23 @@ struct wled_config { bool cs_out_en; bool ext_gen; bool cabc; + bool external_pfet; }; struct wled { const char *name; struct device *dev; struct regmap *regmap; + struct mutex lock; /* Lock to avoid race from ISR */ + ktime_t last_short_event; u16 ctrl_addr; u16 sink_addr; u32 brightness; u32 max_brightness; + u32 short_count; const int *version; + int short_irq; + bool force_mod_disable; struct wled_config cfg; int (*wled_set_brightness)(struct wled *wled, u16 brightness); @@ -192,6 +213,9 @@ static int wled_module_enable(struct wled *wled, int val) { int rc; + if (wled->force_mod_disable) + return 0; + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, WLED3_CTRL_REG_MOD_EN_MASK, @@ -248,12 +272,13 @@ static int wled_update_status(struct backlight_device *bl) bl->props.state & BL_CORE_FBBLANK) brightness = 0; + mutex_lock(&wled->lock); if (brightness) { rc = wled->wled_set_brightness(wled, brightness); if (rc < 0) { dev_err(wled->dev, "wled failed to set brightness rc:%d\n", rc); - return rc; + goto unlock_mutex; } rc = wled->wled_sync_toggle(wled); @@ -267,15 +292,60 @@ static int wled_update_status(struct backlight_device *bl) rc = wled_module_enable(wled, !!brightness); if (rc < 0) { dev_err(wled->dev, "wled enable failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } wled->brightness = brightness; +unlock_mutex: + mutex_unlock(&wled->lock); + return rc; } +#define WLED_SHORT_DLY_MS 20 +#define WLED_SHORT_CNT_MAX 5 +#define WLED_SHORT_RESET_CNT_DLY_USHZ +static irqreturn_t wled_short_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + s64 elapsed_time; + + wled->short_count++; + mutex_lock(&wled->lock); + rc = wled_module_enable(wled, false); + if (rc < 0) { + dev_err(wled->dev, "wled disable failed rc:%d\n", rc); + goto unlock_mutex; + } + + elapsed_time = ktime_us_delta(ktime_get(), + wled->last_short_event); + if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) + wled->short_count = 0; + + if (wled->short_count > WLED_SHORT_CNT_MAX) { + dev_err(wled->dev, "Short trigged %d times, disabling WLED forever!\n", + wled->short_count); + wled->forc
[PATCH V2 2/5] backlight: qcom-wled: Add support for WLED4 peripheral
WLED4 peripheral is present on some PMICs like pmi8998 and pm660l. It has a different register map and also configurations are different. Add support for it. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/qcom-wled.txt | 172 - drivers/video/backlight/qcom-wled.c| 749 +++-- 2 files changed, 696 insertions(+), 225 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt index fb39e32..0ceffa1 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt @@ -1,30 +1,129 @@ Binding for Qualcomm Technologies, Inc. WLED driver -Required properties: -- compatible: should be "qcom,pm8941-wled" -- reg: slave address - -Optional properties: -- default-brightness: brightness value on boot, value from: 0-4095 - default: 2048 -- label: The name of the backlight device -- qcom,cs-out: bool; enable current sink output -- qcom,cabc: bool; enable content adaptive backlight control -- qcom,ext-gen: bool; use externally generated modulator signal to dim -- qcom,current-limit: mA; per-string current limit; value from 0 to 25 - default: 20mA -- qcom,current-boost-limit: mA; boost current limit; one of: - 105, 385, 525, 805, 980, 1260, 1400, 1680 - default: 805mA -- qcom,switching-freq: kHz; switching frequency; one of: - 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, - 1600, 1920, 2400, 3200, 4800, 9600, - default: 1600kHz -- qcom,ovp: V; Over-voltage protection limit; one of: - 27, 29, 32, 35 - default: 29V -- qcom,num-strings: #; number of led strings attached; value from 1 to 3 - default: 2 +WLED (White Light Emitting Diode) driver is used for controlling display +backlight that is part of PMIC on Qualcomm Technologies, Inc. reference +platforms. The PMIC is connected to the host processor via SPMI bus. + +- compatible + Usage:required + Value type: + Definition: should be "qcom,pm8941-wled" or "qcom,pmi8998-wled". + or "qcom,pm660l-wled". + +- reg + Usage:required + Value type: + Definition: Base address of the WLED modules. + +- interrupts + Usage:optional + Value type: + Definition: Interrupts associated with WLED. Interrupts can be + specified as per the encoding listed under + Documentation/devicetree/bindings/spmi/ + qcom,spmi-pmic-arb.txt. + +- interrupt-names + Usage:optional + Value type: + Definition: Interrupt names associated with the interrupts. + Must be "short" and "ovp". The short circuit detection + is not supported for PM8941. + +- label + Usage:required + Value type: + Definition: The name of the backlight device + +- default-brightness + Usage:optional + Value type: + Definition: brightness value on boot, value from: 0-4095 + Default: 2048 + +- qcom,current-limit + Usage:optional + Value type: + Definition: uA; per-string current limit + value: + For pm8941: from 0 to 25000 with 5000 ua step + Default 2 uA + For pmi8998: from 0 to 3 with 5000 ua step + Default 25000 uA. + +- qcom,current-boost-limit + Usage:optional + Value type: + Definition: mA; boost current limit. + For pm8941: one of: 105, 385, 525, 805, 980, 1260, 1400, +1680. Default: 805 mA + For pmi8998: one of: 105, 280, 450, 620, 970, 1150, 1300, + 1500. Default: 970 mA + +- qcom,switching-freq + Usage:optional + Value type: + Definition: kHz; switching frequency; one of: 600, 640, 685, 738, + 800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200, + 4800, 9600. + Default: for pm8941: 1600 kHz + for pmi8998: 800 kHz + +- qcom,ovp + Usage:optional + Value type: + Definition: mV; Over-voltage protection limit; + For pm8941: one of 27000, 29000, 32000, 35000 + Default: 29000 mV + For pmi8998: one of 18100, 19600, 29600, 31100 + Default: 29600 mV + +- qcom,num-strings + Usage:optional + Value type: + Definition: #; number of led strings attached; + for pm8941: va
[PATCH V2 1/5] backlight: qcom-wled: Rename pm8941-wled.c to qcom-wled.c
pm8941-wled.c driver is supporting the WLED peripheral on pm8941. Rename it to qcom-wled.c so that it can support WLED on multiple PMICs. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/{pm8941-wled.txt => qcom-wled.txt}| 2 +- drivers/video/backlight/Kconfig | 8 drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/{pm8941-wled.c => qcom-wled.c}| 0 4 files changed, 6 insertions(+), 6 deletions(-) rename Documentation/devicetree/bindings/leds/backlight/{pm8941-wled.txt => qcom-wled.txt} (95%) rename drivers/video/backlight/{pm8941-wled.c => qcom-wled.c} (100%) diff --git a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt similarity index 95% rename from Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt rename to Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt index e5b294d..fb39e32 100644 --- a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt @@ -1,4 +1,4 @@ -Binding for Qualcomm PM8941 WLED driver +Binding for Qualcomm Technologies, Inc. WLED driver Required properties: - compatible: should be "qcom,pm8941-wled" diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4e1d2ad..8c095e3 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -299,12 +299,12 @@ config BACKLIGHT_TOSA If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its backlight -config BACKLIGHT_PM8941_WLED - tristate "Qualcomm PM8941 WLED Driver" +config BACKLIGHT_QCOM_WLED + tristate "Qualcomm PMIC WLED Driver" select REGMAP help - If you have the Qualcomm PM8941, say Y to enable a driver for the - WLED block. + If you have the Qualcomm PMIC, say Y to enable a driver for the + WLED block. Currently it supports PM8941 and PMI8998. config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 5e28f01..6fd76ef 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -49,8 +49,8 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA)+= pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o -obj-$(CONFIG_BACKLIGHT_PM8941_WLED)+= pm8941-wled.o obj-$(CONFIG_BACKLIGHT_PWM)+= pwm_bl.o +obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o diff --git a/drivers/video/backlight/pm8941-wled.c b/drivers/video/backlight/qcom-wled.c similarity index 100% rename from drivers/video/backlight/pm8941-wled.c rename to drivers/video/backlight/qcom-wled.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 0/5] backlight: qcom-wled: Support for QCOM wled driver
This patch series renames the pm8941-wled.c driver to qcom-wled.c to add the support for multiple PMICs supported by qualcomm. This patch series supports both PM8941 and PMI8998 WLED. The PMI8998 WLED has the support to handle the OVP (over voltage protection) and the SC (short circuit protection) interrupts. It also has the auto calibration algorithm support to configure the right strings if the user specified string configuration is in-correct. These three features are added in this series for PMI8998. changes from v1: Fixed the commit message for backlight: qcom-wled: Rename pm8941-wled.c to qcom-wled.c Kiran Gunda (5): backlight: qcom-wled: Rename pm8941-wled.c to qcom-wled.c backlight: qcom-wled: Add support for WLED4 peripheral backlight: qcom-wled: Add support for short circuit handling backlight: qcom-wled: Add support for OVP interrupt handling backlight: qcom-wled: Add auto string detection logic .../bindings/leds/backlight/pm8941-wled.txt| 42 - .../bindings/leds/backlight/qcom-wled.txt | 158 +++ drivers/video/backlight/Kconfig|8 +- drivers/video/backlight/Makefile |2 +- drivers/video/backlight/pm8941-wled.c | 432 --- drivers/video/backlight/qcom-wled.c| 1329 6 files changed, 1492 insertions(+), 479 deletions(-) delete mode 100644 Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt create mode 100644 Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt delete mode 100644 drivers/video/backlight/pm8941-wled.c create mode 100644 drivers/video/backlight/qcom-wled.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 5/5] backlight: qcom-wled: Add auto string detection logic
The auto string detection algorithm checks if the current WLED sink configuration is valid. It tries enabling every sink and checks if the OVP fault is observed. Based on this information it detects and enables the valid sink configuration. Auto calibration will be triggered when the OVP fault interrupts are seen frequently thereby it tries to fix the sink configuration. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 302 1 file changed, 302 insertions(+) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 80ae084..bacdf3f 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -33,11 +33,14 @@ #define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) #define WLED3_CTRL_REG_INT_RT_STS 0x10 +#define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1) #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) #define WLED3_CTRL_REG_MOD_EN_BIT BIT(7) +#define WLED3_CTRL_REG_FEEDBACK_CONTROL0x48 + #define WLED3_CTRL_REG_FREQ0x4c #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0) @@ -152,6 +155,7 @@ struct wled_config { bool ext_gen; bool cabc; bool external_pfet; + bool auto_detection_enabled; }; struct wled { @@ -160,8 +164,10 @@ struct wled { struct regmap *regmap; struct mutex lock; /* Lock to avoid race from ISR */ ktime_t last_short_event; + ktime_t start_ovp_fault_time; u16 ctrl_addr; u16 sink_addr; + u16 auto_detection_ovp_count; u32 brightness; u32 max_brightness; u32 short_count; @@ -170,6 +176,7 @@ struct wled { int ovp_irq; bool force_mod_disable; bool ovp_irq_disabled; + bool auto_detection_done; struct wled_config cfg; struct delayed_work ovp_work; @@ -386,6 +393,292 @@ static irqreturn_t wled_short_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +#define AUTO_DETECT_BRIGHTNESS 200 +static int wled_auto_string_detection(struct wled *wled) +{ + int rc = 0, i; + u32 sink_config = 0, int_sts; + u8 sink_test = 0, sink_valid = 0, val; + + if (wled->auto_detection_done) + return 0; + + /* read configured sink configuration */ + rc = regmap_read(wled->regmap, wled->sink_addr + +WLED4_SINK_REG_CURR_SINK, &sink_config); + if (rc < 0) { + pr_err("Failed to read SINK configuration rc=%d\n", rc); + goto failed_detect; + } + + /* disable the module before starting detection */ + rc = regmap_update_bits(wled->regmap, + wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, + WLED3_CTRL_REG_MOD_EN_MASK, 0); + if (rc < 0) { + pr_err("Failed to disable WLED module rc=%d\n", rc); + goto failed_detect; + } + + /* set low brightness across all sinks */ + rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS); + if (rc < 0) { + pr_err("Failed to set brightness for auto detection rc=%d\n", + rc); + goto failed_detect; + } + + if (wled->cfg.cabc) { + for (i = 0; i < wled->cfg.num_strings; i++) { + rc = regmap_update_bits(wled->regmap, wled->sink_addr + + WLED4_SINK_REG_STR_CABC(i), + WLED4_SINK_REG_STR_CABC_MASK, + 0); + if (rc < 0) + goto failed_detect; + } + } + + /* disable all sinks */ + rc = regmap_write(wled->regmap, + wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0); + if (rc < 0) { + pr_err("Failed to disable all sinks rc=%d\n", rc); + goto failed_detect; + } + + /* iterate through the strings one by one */ + for (i = 0; i < wled->cfg.num_strings; i++) { + sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i)); + + /* Enable feedback control */ + rc = regmap_write(wled->regmap, wled->ctrl_addr + + WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1); + if (rc < 0) { + pr_err("Failed to enable feedback for SINK %d rc = %d\n", + i + 1, rc); + goto failed_detect; +
[PATCH V1 2/5] backlight: qcom-wled: Add support for WLED4 peripheral
WLED4 peripheral is present on some PMICs like pmi8998 and pm660l. It has a different register map and also configurations are different. Add support for it. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/qcom-wled.txt | 172 - drivers/video/backlight/qcom-wled.c| 749 +++-- 2 files changed, 696 insertions(+), 225 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt index fb39e32..0ceffa1 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt @@ -1,30 +1,129 @@ Binding for Qualcomm Technologies, Inc. WLED driver -Required properties: -- compatible: should be "qcom,pm8941-wled" -- reg: slave address - -Optional properties: -- default-brightness: brightness value on boot, value from: 0-4095 - default: 2048 -- label: The name of the backlight device -- qcom,cs-out: bool; enable current sink output -- qcom,cabc: bool; enable content adaptive backlight control -- qcom,ext-gen: bool; use externally generated modulator signal to dim -- qcom,current-limit: mA; per-string current limit; value from 0 to 25 - default: 20mA -- qcom,current-boost-limit: mA; boost current limit; one of: - 105, 385, 525, 805, 980, 1260, 1400, 1680 - default: 805mA -- qcom,switching-freq: kHz; switching frequency; one of: - 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, - 1600, 1920, 2400, 3200, 4800, 9600, - default: 1600kHz -- qcom,ovp: V; Over-voltage protection limit; one of: - 27, 29, 32, 35 - default: 29V -- qcom,num-strings: #; number of led strings attached; value from 1 to 3 - default: 2 +WLED (White Light Emitting Diode) driver is used for controlling display +backlight that is part of PMIC on Qualcomm Technologies, Inc. reference +platforms. The PMIC is connected to the host processor via SPMI bus. + +- compatible + Usage:required + Value type: + Definition: should be "qcom,pm8941-wled" or "qcom,pmi8998-wled". + or "qcom,pm660l-wled". + +- reg + Usage:required + Value type: + Definition: Base address of the WLED modules. + +- interrupts + Usage:optional + Value type: + Definition: Interrupts associated with WLED. Interrupts can be + specified as per the encoding listed under + Documentation/devicetree/bindings/spmi/ + qcom,spmi-pmic-arb.txt. + +- interrupt-names + Usage:optional + Value type: + Definition: Interrupt names associated with the interrupts. + Must be "short" and "ovp". The short circuit detection + is not supported for PM8941. + +- label + Usage:required + Value type: + Definition: The name of the backlight device + +- default-brightness + Usage:optional + Value type: + Definition: brightness value on boot, value from: 0-4095 + Default: 2048 + +- qcom,current-limit + Usage:optional + Value type: + Definition: uA; per-string current limit + value: + For pm8941: from 0 to 25000 with 5000 ua step + Default 2 uA + For pmi8998: from 0 to 3 with 5000 ua step + Default 25000 uA. + +- qcom,current-boost-limit + Usage:optional + Value type: + Definition: mA; boost current limit. + For pm8941: one of: 105, 385, 525, 805, 980, 1260, 1400, +1680. Default: 805 mA + For pmi8998: one of: 105, 280, 450, 620, 970, 1150, 1300, + 1500. Default: 970 mA + +- qcom,switching-freq + Usage:optional + Value type: + Definition: kHz; switching frequency; one of: 600, 640, 685, 738, + 800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200, + 4800, 9600. + Default: for pm8941: 1600 kHz + for pmi8998: 800 kHz + +- qcom,ovp + Usage:optional + Value type: + Definition: mV; Over-voltage protection limit; + For pm8941: one of 27000, 29000, 32000, 35000 + Default: 29000 mV + For pmi8998: one of 18100, 19600, 29600, 31100 + Default: 29600 mV + +- qcom,num-strings + Usage:optional + Value type: + Definition: #; number of led strings attached; + for pm8941: va
[PATCH V1 3/5] backlight: qcom-wled: Add support for short circuit handling
Handle the short circuit interrupt and check if the short circuit interrupt is valid. Re-enable the module to check if it goes away. Disable the module altogether if the short circuit event persists. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 134 ++-- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index be8b8d3..2cfba77 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +#include +#include +#include #include #include #include @@ -23,7 +26,9 @@ #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF -/* Control registers */ +/* WLED3 Control registers */ +#define WLED3_CTRL_REG_FAULT_STATUS0x08 + #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) @@ -36,7 +41,17 @@ #define WLED3_CTRL_REG_ILIMIT 0x4e #define WLED3_CTRL_REG_ILIMIT_MASKGENMASK(2, 0) -/* sink registers */ +/* WLED4 control registers */ +#define WLED4_CTRL_REG_SHORT_PROTECT 0x5e +#define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7) + +#define WLED4_CTRL_REG_SEC_ACCESS 0xd0 +#define WLED4_CTRL_REG_SEC_UNLOCK 0xa5 + +#define WLED4_CTRL_REG_TEST1 0xe2 +#define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09 + +/* WLED3 sink registers */ #define WLED3_SINK_REG_SYNC0x47 #define WLED3_SINK_REG_SYNC_MASK GENMASK(2, 0) #define WLED4_SINK_REG_SYNC_MASK GENMASK(3, 0) @@ -130,17 +145,23 @@ struct wled_config { bool cs_out_en; bool ext_gen; bool cabc; + bool external_pfet; }; struct wled { const char *name; struct device *dev; struct regmap *regmap; + struct mutex lock; /* Lock to avoid race from ISR */ + ktime_t last_short_event; u16 ctrl_addr; u16 sink_addr; u32 brightness; u32 max_brightness; + u32 short_count; const int *version; + int short_irq; + bool force_mod_disable; struct wled_config cfg; int (*wled_set_brightness)(struct wled *wled, u16 brightness); @@ -192,6 +213,9 @@ static int wled_module_enable(struct wled *wled, int val) { int rc; + if (wled->force_mod_disable) + return 0; + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, WLED3_CTRL_REG_MOD_EN_MASK, @@ -248,12 +272,13 @@ static int wled_update_status(struct backlight_device *bl) bl->props.state & BL_CORE_FBBLANK) brightness = 0; + mutex_lock(&wled->lock); if (brightness) { rc = wled->wled_set_brightness(wled, brightness); if (rc < 0) { dev_err(wled->dev, "wled failed to set brightness rc:%d\n", rc); - return rc; + goto unlock_mutex; } rc = wled->wled_sync_toggle(wled); @@ -267,15 +292,60 @@ static int wled_update_status(struct backlight_device *bl) rc = wled_module_enable(wled, !!brightness); if (rc < 0) { dev_err(wled->dev, "wled enable failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } wled->brightness = brightness; +unlock_mutex: + mutex_unlock(&wled->lock); + return rc; } +#define WLED_SHORT_DLY_MS 20 +#define WLED_SHORT_CNT_MAX 5 +#define WLED_SHORT_RESET_CNT_DLY_USHZ +static irqreturn_t wled_short_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + s64 elapsed_time; + + wled->short_count++; + mutex_lock(&wled->lock); + rc = wled_module_enable(wled, false); + if (rc < 0) { + dev_err(wled->dev, "wled disable failed rc:%d\n", rc); + goto unlock_mutex; + } + + elapsed_time = ktime_us_delta(ktime_get(), + wled->last_short_event); + if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) + wled->short_count = 0; + + if (wled->short_count > WLED_SHORT_CNT_MAX) { + dev_err(wled->dev, "Short trigged %d times, disabling WLED forever!\n", + wled->short_count); + wled->forc
[PATCH V1 4/5] backlight: qcom-wled: Add support for OVP interrupt handling
WLED peripheral has over voltage protection(OVP) circuitry and the OVP fault is notified through an interrupt. Though this fault condition rising is due to an incorrect hardware configuration is mitigated in the hardware, it still needs to be detected and handled. Add support for it. When WLED module is enabled, keep OVP fault interrupt disabled for 10 ms to account for soft start delay. Signed-off-by: Kiran Gunda --- drivers/video/backlight/qcom-wled.c | 118 +++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 2cfba77..80ae084 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -23,14 +23,20 @@ /* From DT binding */ #define WLED_DEFAULT_BRIGHTNESS2048 - +#define WLED_SOFT_START_DLY_US 1 #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF /* WLED3 Control registers */ #define WLED3_CTRL_REG_FAULT_STATUS0x08 +#define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0) +#define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1) +#define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) + +#define WLED3_CTRL_REG_INT_RT_STS 0x10 #define WLED3_CTRL_REG_MOD_EN 0x46 #define WLED3_CTRL_REG_MOD_EN_MASKBIT(7) +#define WLED3_CTRL_REG_MOD_EN_BIT BIT(7) #define WLED3_CTRL_REG_FREQ0x4c #define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0) @@ -161,9 +167,12 @@ struct wled { u32 short_count; const int *version; int short_irq; + int ovp_irq; bool force_mod_disable; + bool ovp_irq_disabled; struct wled_config cfg; + struct delayed_work ovp_work; int (*wled_set_brightness)(struct wled *wled, u16 brightness); int (*wled_sync_toggle)(struct wled *wled); }; @@ -209,6 +218,32 @@ static int wled4_set_brightness(struct wled *wled, u16 brightness) return 0; } +static void wled_ovp_work(struct work_struct *work) +{ + u32 val; + int rc; + + struct wled *wled = container_of(work, +struct wled, ovp_work.work); + + rc = regmap_read(wled->regmap, wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN, +&val); + if (rc < 0) + return; + + if (val & WLED3_CTRL_REG_MOD_EN_BIT) { + if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) { + enable_irq(wled->ovp_irq); + wled->ovp_irq_disabled = false; + } + } else { + if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) { + disable_irq(wled->ovp_irq); + wled->ovp_irq_disabled = true; + } + } +} + static int wled_module_enable(struct wled *wled, int val) { int rc; @@ -220,7 +255,12 @@ static int wled_module_enable(struct wled *wled, int val) WLED3_CTRL_REG_MOD_EN, WLED3_CTRL_REG_MOD_EN_MASK, WLED3_CTRL_REG_MOD_EN_MASK); - return rc; + if (rc < 0) + return rc; + + schedule_delayed_work(&wled->ovp_work, WLED_SOFT_START_DLY_US); + + return 0; } static int wled3_sync_toggle(struct wled *wled) @@ -346,6 +386,36 @@ static irqreturn_t wled_short_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +static irqreturn_t wled_ovp_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + u32 int_sts, fault_sts; + + rc = regmap_read(wled->regmap, +wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, &int_sts); + if (rc < 0) { + dev_err(wled->dev, "Error in reading WLED3_INT_RT_STS rc=%d\n", + rc); + return IRQ_HANDLED; + } + + rc = regmap_read(wled->regmap, wled->ctrl_addr + +WLED3_CTRL_REG_FAULT_STATUS, &fault_sts); + if (rc < 0) { + dev_err(wled->dev, "Error in reading WLED_FAULT_STATUS rc=%d\n", + rc); + return IRQ_HANDLED; + } + + if (fault_sts & + (WLED3_CTRL_REG_OVP_FAULT_BIT | WLED3_CTRL_REG_ILIM_FAULT_BIT)) + dev_dbg(wled->dev, "WLED OVP fault detected, int_sts=%x fault_sts= %x\n", + int_sts, fault_sts); + + return IRQ_HANDLED; +} + static int wled3_setup(struct wled *wled) { u16 addr; @@ -821,6 +891,44 @@ static int wled_configure_short_irq(struct wled *wled, return
[PATCH V1 1/5] qcom: wled: Rename pm8941-wled.c to qcom-wled.c
pm8941-wled.c driver is supporting the WLED peripheral on pm8941. Rename it to qcom-wled.c so that it can support WLED on multiple PMICs. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/{pm8941-wled.txt => qcom-wled.txt}| 2 +- drivers/video/backlight/Kconfig | 8 drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/{pm8941-wled.c => qcom-wled.c}| 0 4 files changed, 6 insertions(+), 6 deletions(-) rename Documentation/devicetree/bindings/leds/backlight/{pm8941-wled.txt => qcom-wled.txt} (95%) rename drivers/video/backlight/{pm8941-wled.c => qcom-wled.c} (100%) diff --git a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt similarity index 95% rename from Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt rename to Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt index e5b294d..fb39e32 100644 --- a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt @@ -1,4 +1,4 @@ -Binding for Qualcomm PM8941 WLED driver +Binding for Qualcomm Technologies, Inc. WLED driver Required properties: - compatible: should be "qcom,pm8941-wled" diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4e1d2ad..8c095e3 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -299,12 +299,12 @@ config BACKLIGHT_TOSA If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its backlight -config BACKLIGHT_PM8941_WLED - tristate "Qualcomm PM8941 WLED Driver" +config BACKLIGHT_QCOM_WLED + tristate "Qualcomm PMIC WLED Driver" select REGMAP help - If you have the Qualcomm PM8941, say Y to enable a driver for the - WLED block. + If you have the Qualcomm PMIC, say Y to enable a driver for the + WLED block. Currently it supports PM8941 and PMI8998. config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 5e28f01..6fd76ef 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -49,8 +49,8 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA)+= pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o -obj-$(CONFIG_BACKLIGHT_PM8941_WLED)+= pm8941-wled.o obj-$(CONFIG_BACKLIGHT_PWM)+= pwm_bl.o +obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o diff --git a/drivers/video/backlight/pm8941-wled.c b/drivers/video/backlight/qcom-wled.c similarity index 100% rename from drivers/video/backlight/pm8941-wled.c rename to drivers/video/backlight/qcom-wled.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 0/5] backlight: qcom-wled: Support for QCOM wled driver
This patch series renames the pm8941-wled.c driver to qcom-wled.c to add the support for multiple PMICs supported by qualcomm. This patch series supports both PM8941 and PMI8998 WLED. The PMI8998 WLED has the support to handle the OVP (over voltage protection) and the SC (short circuit protection) interrupts. It also has the auto calibration algorithm support to configure the right strings if the user specified string configuration is in-correct. These three features are added in this series for PMI8998. Kiran Gunda (5): qcom: wled: Rename pm8941-wled.c to qcom-wled.c backlight: qcom-wled: Add support for WLED4 peripheral backlight: qcom-wled: Add support for short circuit handling backlight: qcom-wled: Add support for OVP interrupt handling backlight: qcom-wled: Add auto string detection logic .../bindings/leds/backlight/pm8941-wled.txt| 42 - .../bindings/leds/backlight/qcom-wled.txt | 158 +++ drivers/video/backlight/Kconfig|8 +- drivers/video/backlight/Makefile |2 +- drivers/video/backlight/pm8941-wled.c | 432 --- drivers/video/backlight/qcom-wled.c| 1329 6 files changed, 1492 insertions(+), 479 deletions(-) delete mode 100644 Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt create mode 100644 Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt delete mode 100644 drivers/video/backlight/pm8941-wled.c create mode 100644 drivers/video/backlight/qcom-wled.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 3/4] qcom: spmi-wled: Add support for OVP interrupt handling
WLED peripheral has over voltage protection(OVP) circuitry and the OVP fault is notified through an interrupt. Though this fault condition rising is due to an incorrect hardware configuration is mitigated in the hardware, it still needs to be detected and handled. Add support for it. When WLED module is enabled, keep OVP fault interrupt disabled for 10 ms to account for soft start delay. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/qcom-spmi-wled.txt | 7 +- drivers/video/backlight/qcom-spmi-wled.c | 83 ++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt index 768608c..d39ee93 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -92,7 +92,7 @@ The PMIC is connected to the host processor via SPMI bus. Usage: optional Value type: Definition: Interrupt names associated with the interrupts. - Must be "sc-irq". + Currently supported interrupts are "sc-irq" and "ovp-irq". Example: @@ -102,8 +102,9 @@ qcom-wled@d800 { reg-names = "qcom-wled-ctrl-base", "qcom-wled-sink-base"; label = "backlight"; - interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "sc-irq"; + interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq", "ovp-irq"; qcom,fs-current-limit = <25000>; qcom,current-boost-limit = <970>; qcom,switching-freq = <800>; diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index 7dbaaa7..8b2a77a 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -29,9 +29,15 @@ #define QCOM_WLED_SC_DLY_MS20 #define QCOM_WLED_SC_CNT_MAX 5 #define QCOM_WLED_SC_RESET_CNT_DLY_US 100 +#define QCOM_WLED_SOFT_START_DLY_US1 /* WLED control registers */ #define QCOM_WLED_CTRL_FAULT_STATUS0x08 +#define QCOM_WLED_CTRL_ILIM_FAULT_BIT BIT(0) +#define QCOM_WLED_CTRL_OVP_FAULT_BIT BIT(1) +#define QCOM_WLED_CTRL_SC_FAULT_BIT BIT(2) + +#define QCOM_WLED_CTRL_INT_RT_STS 0x10 #define QCOM_WLED_CTRL_MOD_ENABLE 0x46 #define QCOM_WLED_CTRL_MOD_EN_MASKBIT(7) @@ -90,6 +96,7 @@ struct qcom_wled_config { u32 fs_current; u32 string_cfg; int sc_irq; + int ovp_irq; bool en_cabc; bool ext_pfet_sc_pro_en; }; @@ -106,6 +113,7 @@ struct qcom_wled { u32 brightness; u32 sc_count; bool prev_state; + bool ovp_irq_disabled; }; static int qcom_wled_module_enable(struct qcom_wled *wled, int val) @@ -115,6 +123,28 @@ static int qcom_wled_module_enable(struct qcom_wled *wled, int val) rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + QCOM_WLED_CTRL_MOD_ENABLE, QCOM_WLED_CTRL_MOD_EN_MASK, val << QCOM_WLED_CTRL_MODULE_EN_SHIFT); + if (rc < 0) + return rc; + /* +* Wait for at least 10ms before enabling OVP fault interrupt after +* enabling the module so that soft start is completed. Keep the OVP +* interrupt disabled when the module is disabled. +*/ + if (val) { + usleep_range(QCOM_WLED_SOFT_START_DLY_US, + QCOM_WLED_SOFT_START_DLY_US + 1000); + + if (wled->cfg.ovp_irq > 0 && wled->ovp_irq_disabled) { + enable_irq(wled->cfg.ovp_irq); + wled->ovp_irq_disabled = false; + } + } else { + if (wled->cfg.ovp_irq > 0 && !wled->ovp_irq_disabled) { + disable_irq(wled->cfg.ovp_irq); + wled->ovp_irq_disabled = true; + } + } + return rc; } @@ -264,12 +294,42 @@ static irqreturn_t qcom_wled_sc_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +static irqreturn_t qcom_wled_ovp_irq_handler(int irq, void *_wled) +{ + struct qcom_wled *wled = _wled; + int rc; + u32 int_sts, fault_sts; + + rc = regmap_read(wled->regmap, + wled->ctrl_addr + QCOM_WLED_CTRL_INT_RT_STS, &int_sts); + if (rc < 0) { + pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc); + return IRQ_HANDLED; + } + +
[PATCH V1 4/4] qcom: spmi-wled: Add auto-calibration logic support
The auto-calibration algorithm checks if the current WLED sink configuration is valid. It tries enabling every sink and checks if the OVP fault is observed. Based on this information it detects and enables the valid sink configuration. Auto calibration will be triggered when the OVP fault interrupts are seen frequently thereby it tries to fix the sink configuration. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/qcom-spmi-wled.txt | 5 + drivers/video/backlight/qcom-spmi-wled.c | 304 - 2 files changed, 306 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt index d39ee93..f06c0cd 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -94,6 +94,11 @@ The PMIC is connected to the host processor via SPMI bus. Definition: Interrupt names associated with the interrupts. Currently supported interrupts are "sc-irq" and "ovp-irq". +- qcom,auto-calibration + Usage: optional + Value type: + Definition: Enables auto-calibration of the WLED sink configuration. + Example: qcom-wled@d800 { diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index 8b2a77a..aee5c56 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -38,11 +38,14 @@ #define QCOM_WLED_CTRL_SC_FAULT_BIT BIT(2) #define QCOM_WLED_CTRL_INT_RT_STS 0x10 +#define QCOM_WLED_CTRL_OVP_FLT_RT_STS_BIT BIT(1) #define QCOM_WLED_CTRL_MOD_ENABLE 0x46 #define QCOM_WLED_CTRL_MOD_EN_MASKBIT(7) #define QCOM_WLED_CTRL_MODULE_EN_SHIFT7 +#define QCOM_WLED_CTRL_FDBK_OP 0x48 + #define QCOM_WLED_CTRL_SWITCH_FREQ 0x4c #define QCOM_WLED_CTRL_SWITCH_FREQ_MASK GENMASK(3, 0) @@ -99,6 +102,7 @@ struct qcom_wled_config { int ovp_irq; bool en_cabc; bool ext_pfet_sc_pro_en; + bool auto_calib_enabled; }; struct qcom_wled { @@ -108,18 +112,25 @@ struct qcom_wled { struct mutex lock; struct qcom_wled_config cfg; ktime_t last_sc_event_time; + ktime_t start_ovp_fault_time; u16 sink_addr; u16 ctrl_addr; + u16 auto_calibration_ovp_count; u32 brightness; u32 sc_count; bool prev_state; bool ovp_irq_disabled; + bool auto_calib_done; + bool force_mod_disable; }; static int qcom_wled_module_enable(struct qcom_wled *wled, int val) { int rc; + if (wled->force_mod_disable) + return 0; + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + QCOM_WLED_CTRL_MOD_ENABLE, QCOM_WLED_CTRL_MOD_EN_MASK, val << QCOM_WLED_CTRL_MODULE_EN_SHIFT); @@ -187,12 +198,10 @@ static int qcom_wled_set_brightness(struct qcom_wled *wled, u16 brightness) v[1] = (brightness >> 8) & 0xf; for (i = 0; (string_cfg >> i) != 0; i++) { - if (string_cfg & BIT(i)) { rc = regmap_bulk_write(wled->regmap, wled->sink_addr + QCOM_WLED_SINK_BRIGHT_LSB_REG(i), v, 2); if (rc < 0) return rc; - } } return 0; @@ -294,6 +303,262 @@ static irqreturn_t qcom_wled_sc_irq_handler(int irq, void *_wled) return IRQ_HANDLED; } +#define AUTO_CALIB_BRIGHTNESS 200 +static int qcom_wled_auto_calibrate(struct qcom_wled *wled) +{ + int rc = 0, i; + u32 sink_config = 0, int_sts; + u8 reg = 0, sink_test = 0, sink_valid = 0; + u8 string_cfg = wled->cfg.string_cfg; + + /* read configured sink configuration */ + rc = regmap_read(wled->regmap, wled->sink_addr + + QCOM_WLED_SINK_CURR_SINK_EN, &sink_config); + if (rc < 0) { + pr_err("Failed to read SINK configuration rc=%d\n", rc); + goto failed_calib; + } + + /* disable the module before starting calibration */ + rc = regmap_update_bits(wled->regmap, + wled->ctrl_addr + QCOM_WLED_CTRL_MOD_ENABLE, + QCOM_WLED_CTRL_MOD_EN_MASK, 0); + if (rc < 0) { + pr_err("Failed to disable WLED module rc=%d\n", rc); + goto failed_calib; + } + + /* set low brightness across all sinks */ + rc = qcom_wled_set_brightness(wled, AUTO_CALIB_BRIGHTNESS); + if (rc < 0) { + pr_err("Failed to set brightness for calibration rc=%
[PATCH V1 1/4] qcom: spmi-wled: Add support for qcom wled driver
WLED driver provides the interface to the display driver to adjust the brightness of the display backlight. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/qcom-spmi-wled.txt | 90 drivers/video/backlight/Kconfig| 9 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/qcom-spmi-wled.c | 504 + 4 files changed, 604 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt create mode 100644 drivers/video/backlight/qcom-spmi-wled.c diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt new file mode 100644 index 000..f1ea25b --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -0,0 +1,90 @@ +Binding for Qualcomm WLED driver + +WLED (White Light Emitting Diode) driver is used for controlling display +backlight that is part of PMIC on Qualcomm Technologies reference platforms. +The PMIC is connected to the host processor via SPMI bus. + +- compatible + Usage: required + Value type: + Definition: should be "qcom,pm8998-spmi-wled". + +- reg + Usage: required + Value type: + Definition: Base address and size of the WLED modules. + +- reg-names + Usage: required + Value type: + Definition: Names associated with base addresses. should be +"qcom-wled-ctrl-base", "qcom-wled-sink-base". + +- label + Usage: required + Value type: + Definition: The name of the backlight device. + +- default-brightness + Usage: optional + Value type: + Definition: brightness value on boot, value from: 0-4095 + default: 2048 + +- qcom,fs-current-limit + Usage: optional + Value type: + Definition: per-string full scale current limit in uA. value from + 0 to 3 with 5000 uA resolution. default: 25000 uA + +- qcom,current-boost-limit + Usage: optional + Value type: + Definition: ILIM threshold in mA. values are 105, 280, 450, 620, 970, + 1150, 1300, 1500. default: 970 mA + +- qcom,switching-freq + Usage: optional + Value type: + Definition: Switching frequency in KHz. values are + 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, + 1600, 1920, 2400, 3200, 4800, 9600. + default: 800 KHz + +- qcom,ovp + Usage: optional + Value type: + Definition: Over-voltage protection limit in mV. values are 31100, + 29600, 19600, 18100. + default: 29600 mV + +- qcom,string-cfg + Usage: optional + Value type: + Definition: Bit mask of the wled strings. Bit 0 to 3 indicates strings + 0 to 3 respectively. Wled module has four strings of leds + numbered from 0 to 3. Each string of leds are operated + individually. Specify the strings using the bit mask. Any + combination of led strings can be used. + default value is 15 (b). + +- qcom,en-cabc + Usage: optional + Value type: + Definition: Specify if cabc (content adaptive backlight control) is + needed. + +Example: + +qcom-wled@d800 { + compatible = "qcom,pm8998-spmi-wled"; + reg = <0xd800 0xd900>; + reg-names = "qcom-wled-ctrl-base", "qcom-wled-sink-base"; + label = "backlight"; + + qcom,fs-current-limit = <25000>; + qcom,current-boost-limit = <970>; + qcom,switching-freq = <800>; + qcom,ovp = <29600>; + qcom,string-cfg = <15>; +}; diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4e1d2ad..19ea799 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -306,6 +306,15 @@ config BACKLIGHT_PM8941_WLED If you have the Qualcomm PM8941, say Y to enable a driver for the WLED block. +config BACKLIGHT_QCOM_SPMI_WLED + tristate "Qualcomm WLED Driver" + select REGMAP + help + If you have the Qualcomm WLED used for backlight control, say Y to + enable a driver for the WLED block. This driver provides the + interface to the display driver to adjust the brightness of the + display backlight. This supports PMI8998 currently. + config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" depends on X86 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 5e28f01..f6627e5 100644 --- a/drivers/video/backlight/Makefi
[PATCH V1 2/4] qcom: spmi-wled: Add support for short circuit handling
Handle the short circuit(SC) interrupt and check if the SC interrupt is valid. Re-enable the module to check if it goes away. Disable the module altogether if the SC event persists. Signed-off-by: Kiran Gunda --- .../bindings/leds/backlight/qcom-spmi-wled.txt | 22 drivers/video/backlight/qcom-spmi-wled.c | 126 - 2 files changed, 142 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt index f1ea25b..768608c 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -74,6 +74,26 @@ The PMIC is connected to the host processor via SPMI bus. Definition: Specify if cabc (content adaptive backlight control) is needed. +- qcom,ext-pfet-sc-pro-en + Usage: optional + Value type: + Definition: Specify if external PFET control for short circuit + protection is needed. + +- interrupts + Usage: optional + Value type: + Definition: Interrupts associated with WLED. Interrupts can be + specified as per the encoding listed under + Documentation/devicetree/bindings/spmi/ + qcom,spmi-pmic-arb.txt. + +- interrupt-names + Usage: optional + Value type: + Definition: Interrupt names associated with the interrupts. + Must be "sc-irq". + Example: qcom-wled@d800 { @@ -82,6 +102,8 @@ qcom-wled@d800 { reg-names = "qcom-wled-ctrl-base", "qcom-wled-sink-base"; label = "backlight"; + interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; qcom,fs-current-limit = <25000>; qcom,current-boost-limit = <970>; qcom,switching-freq = <800>; diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index 14c3adc..7dbaaa7 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -11,6 +11,9 @@ * GNU General Public License for more details. */ +#include +#include +#include #include #include #include @@ -23,7 +26,13 @@ #define QCOM_WLED_DEFAULT_BRIGHTNESS 2048 #define QCOM_WLED_MAX_BRIGHTNESS 4095 +#define QCOM_WLED_SC_DLY_MS20 +#define QCOM_WLED_SC_CNT_MAX 5 +#define QCOM_WLED_SC_RESET_CNT_DLY_US 100 + /* WLED control registers */ +#define QCOM_WLED_CTRL_FAULT_STATUS0x08 + #define QCOM_WLED_CTRL_MOD_ENABLE 0x46 #define QCOM_WLED_CTRL_MOD_EN_MASKBIT(7) #define QCOM_WLED_CTRL_MODULE_EN_SHIFT7 @@ -37,6 +46,15 @@ #define QCOM_WLED_CTRL_ILIM0x4e #define QCOM_WLED_CTRL_ILIM_MASK GENMASK(2, 0) +#define QCOM_WLED_CTRL_SHORT_PROTECT 0x5e +#define QCOM_WLED_CTRL_SHORT_EN_MASK BIT(7) + +#define QCOM_WLED_CTRL_SEC_ACCESS 0xd0 +#define QCOM_WLED_CTRL_SEC_UNLOCK 0xa5 + +#define QCOM_WLED_CTRL_TEST1 0xe2 +#define QCOM_WLED_EXT_FET_DTEST2 0x09 + /* WLED sink registers */ #define QCOM_WLED_SINK_CURR_SINK_EN0x46 #define QCOM_WLED_SINK_CURR_SINK_MASK GENMASK(7, 4) @@ -71,19 +89,23 @@ struct qcom_wled_config { u32 switch_freq; u32 fs_current; u32 string_cfg; + int sc_irq; bool en_cabc; + bool ext_pfet_sc_pro_en; }; struct qcom_wled { const char *name; struct platform_device *pdev; struct regmap *regmap; + struct mutex lock; + struct qcom_wled_config cfg; + ktime_t last_sc_event_time; u16 sink_addr; u16 ctrl_addr; u32 brightness; + u32 sc_count; bool prev_state; - - struct qcom_wled_config cfg; }; static int qcom_wled_module_enable(struct qcom_wled *wled, int val) @@ -157,25 +179,26 @@ static int qcom_wled_update_status(struct backlight_device *bl) bl->props.state & BL_CORE_FBBLANK) brightness = 0; + mutex_lock(&wled->lock); if (brightness) { rc = qcom_wled_set_brightness(wled, brightness); if (rc < 0) { pr_err("wled failed to set brightness rc:%d\n", rc); - return rc; + goto unlock_mutex; } if (!!brightness != wled->prev_state) { rc = qcom_wled_module_enable(wled, !!brightness); if (rc < 0) { pr_err("wled enable fa
[PATCH V1 0/4] qcom: spmi-wled: Support for QCOM wled driver
WLED driver provides the interface to the display driver to adjust the brightness of the display backlight. This driver exposes two APIs to set and get the brightness of the display backlight through the backlight framework. This driver has the support to handle the OVP (over voltage protection) and the SC (short circuit protection) interrupts. It also has the auto calibration algorithm support to configure the right strings if the user specified string configuration is in-correct. Kiran Gunda (4): qcom: spmi-wled: Add support for qcom wled driver qcom: spmi-wled: Add support for short circuit handling qcom: spmi-wled: Add support for OVP interrupt handling qcom: spmi-wled: Add auto-calibration logic support .../bindings/leds/backlight/qcom-spmi-wled.txt | 118 +++ drivers/video/backlight/Kconfig| 9 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/qcom-spmi-wled.c | 999 + 4 files changed, 1127 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt create mode 100644 drivers/video/backlight/qcom-spmi-wled.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2] spmi: pmic-arb: Move the ownership check to irq_chip callback
Check the irq ownership in the irq_request_resources callback instead of checking it during the irq mapping. This can prevent installing the flow handler for the interrupt that is not owned by the EE and allow the irq translation during the gpio driver probe. Signed-off-by: Kiran Gunda --- V2: Fixed commit message. V1: This patch depends on the below patch series. Please take this patch along with this series. drivers/spmi/spmi-pmic-arb.c | 26 +++--- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index ca9bdd3..360b821 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -666,6 +666,24 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, return 0; } +static int qpnpint_irq_request_resources(struct irq_data *d) +{ + struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); + u16 periph = hwirq_to_per(d->hwirq); + u16 apid = hwirq_to_apid(d->hwirq); + u16 sid = hwirq_to_sid(d->hwirq); + u16 irq = hwirq_to_irq(d->hwirq); + + if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { + dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", + sid, periph, irq, pmic_arb->ee, + pmic_arb->apid_data[apid].irq_ee); + return -ENODEV; + } + + return 0; +} + static struct irq_chip pmic_arb_irqchip = { .name = "pmic_arb", .irq_ack= qpnpint_irq_ack, @@ -674,6 +692,7 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, .irq_set_type = qpnpint_irq_set_type, .irq_set_wake = qpnpint_irq_set_wake, .irq_get_irqchip_state = qpnpint_get_irqchip_state, + .irq_request_resources = qpnpint_irq_request_resources, .flags = IRQCHIP_MASK_ON_SUSPEND, }; @@ -707,13 +726,6 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, } apid = rc; - if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { - dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", - intspec[0], intspec[1], intspec[2], pmic_arb->ee, - pmic_arb->apid_data[apid].irq_ee); - return -ENODEV; - } - /* Keep track of {max,min}_apid for bounding search during interrupt */ if (apid > pmic_arb->max_apid) pmic_arb->max_apid = apid; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1] spmi: pmic-arb: Move the ownership check to irq_chip callback
Check the irq ownership in the irq_request_resources callback instead of checking it during the irq mapping. That we can prevent installing the flow handler for the interrupt that is not owned by the EE and allow the irq translation during the gpio driver probe. Signed-off-by: Kiran Gunda --- This patch depends on the below patch series. Please take this patch along with this series. [PATCH V2 00/12]: spmi: pmic-arb: Support for HW v5 and other fixes drivers/spmi/spmi-pmic-arb.c | 26 +++--- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index ca9bdd3..360b821 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -666,6 +666,24 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, return 0; } +static int qpnpint_irq_request_resources(struct irq_data *d) +{ + struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); + u16 periph = hwirq_to_per(d->hwirq); + u16 apid = hwirq_to_apid(d->hwirq); + u16 sid = hwirq_to_sid(d->hwirq); + u16 irq = hwirq_to_irq(d->hwirq); + + if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { + dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", + sid, periph, irq, pmic_arb->ee, + pmic_arb->apid_data[apid].irq_ee); + return -ENODEV; + } + + return 0; +} + static struct irq_chip pmic_arb_irqchip = { .name = "pmic_arb", .irq_ack= qpnpint_irq_ack, @@ -674,6 +692,7 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, .irq_set_type = qpnpint_irq_set_type, .irq_set_wake = qpnpint_irq_set_wake, .irq_get_irqchip_state = qpnpint_get_irqchip_state, + .irq_request_resources = qpnpint_irq_request_resources, .flags = IRQCHIP_MASK_ON_SUSPEND, }; @@ -707,13 +726,6 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, } apid = rc; - if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { - dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", - intspec[0], intspec[1], intspec[2], pmic_arb->ee, - pmic_arb->apid_data[apid].irq_ee); - return -ENODEV; - } - /* Keep track of {max,min}_apid for bounding search during interrupt */ if (apid > pmic_arb->max_apid) pmic_arb->max_apid = apid; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2] spmi: pmic-arb: Enforce the ownership check optionally
The peripheral ownership check is not necessary on single master platforms. Hence, enforce the peripheral ownership check optionally. Signed-off-by: Kiran Gunda Tested-by: Shawn Guo --- v2: Fixed the commit message. Added Shawn's 'Tested-by' tag. v1: This patch depends on the below patch series. Please take this patch along with this series. [PATCH V2 00/12]: spmi: pmic-arb: Support for HW v5 and other fixes Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt | 6 ++ drivers/spmi/spmi-pmic-arb.c | 7 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt index e16b9b5..da708e8 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt @@ -42,6 +42,10 @@ Required properties: cell 4: interrupt flags indicating level-sense information, as defined in dt-bindings/interrupt-controller/irq.h +Optional properties: +- qcom,enforce-ownership : A boolean property. If defined the peripheral + ownership check is enforced. Otherwise the ownership + check is ignored. Example: spmi { @@ -62,4 +66,6 @@ Example: interrupt-controller; #interrupt-cells = <4>; + + qcom,enforce-ownership; }; diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index ca9bdd3..354c949 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -167,6 +167,7 @@ struct spmi_pmic_arb { u16 *ppid_to_apid; u16 last_apid; struct apid_dataapid_data[PMIC_ARB_MAX_PERIPHS]; + boolenforce_ownership; }; /** @@ -707,7 +708,8 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, } apid = rc; - if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { + if (pmic_arb->enforce_ownership && + pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", intspec[0], intspec[1], intspec[2], pmic_arb->ee, pmic_arb->apid_data[apid].irq_ee); @@ -1236,6 +1238,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) } pmic_arb->ee = ee; + pmic_arb->enforce_ownership = + of_property_read_bool(pdev->dev.of_node, "qcom,enforce-ownership"); + mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS, sizeof(*mapping_table), GFP_KERNEL); if (!mapping_table) { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] spmi: pmic-arb: Enforce the ownership check optionally
The peripheral ownership check is not necessary on single master platforms. Hence, enforce the peripheral ownership check optioanlly. Signed-off-by: Kiran Gunda --- This patch depends on the below patch series. Please take this patch along with this series. [PATCH V2 00/12]: spmi: pmic-arb: Support for HW v5 and other fixes Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt | 6 ++ drivers/spmi/spmi-pmic-arb.c | 7 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt index e16b9b5..da708e8 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt @@ -42,6 +42,10 @@ Required properties: cell 4: interrupt flags indicating level-sense information, as defined in dt-bindings/interrupt-controller/irq.h +Optional properties: +- qcom,enforce-ownership : A boolean property. If defined the peripheral + ownership check is enforced. Otherwise the ownership + check is ignored. Example: spmi { @@ -62,4 +66,6 @@ Example: interrupt-controller; #interrupt-cells = <4>; + + qcom,enforce-ownership; }; diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index ca9bdd3..354c949 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -167,6 +167,7 @@ struct spmi_pmic_arb { u16 *ppid_to_apid; u16 last_apid; struct apid_dataapid_data[PMIC_ARB_MAX_PERIPHS]; + boolenforce_ownership; }; /** @@ -707,7 +708,8 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, } apid = rc; - if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { + if (pmic_arb->enforce_ownership && + pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", intspec[0], intspec[1], intspec[2], pmic_arb->ee, pmic_arb->apid_data[apid].irq_ee); @@ -1236,6 +1238,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) } pmic_arb->ee = ee; + pmic_arb->enforce_ownership = + of_property_read_bool(pdev->dev.of_node, "qcom,enforce-ownership"); + mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS, sizeof(*mapping_table), GFP_KERNEL); if (!mapping_table) { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 01/12] spmi: pmic-arb: remove the read/write access checks
The access mode checks for peripheral ownership for read/write permissions should not be required. Every peripheral enabled for this master is expected to have a read/write permissions. If there is any such invalid access due to wrong configuration in boot loader or device tree files, then it should be fixed in those locations. Hence, remove the access mode checks from the driver. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 75 +++- 1 file changed, 5 insertions(+), 70 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index f4b7a98..7531519 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -128,7 +128,6 @@ struct apid_data { * @ee:the current Execution Environment * @min_apid: minimum APID (used for bounding IRQ search) * @max_apid: maximum APID - * @max_periph:maximum number of PMIC peripherals supported by HW. * @mapping_table: in-memory copy of PPID -> APID mapping table. * @domain:irq domain object for PMIC IRQ domain * @spmic: SPMI controller object @@ -148,7 +147,6 @@ struct spmi_pmic_arb { u8 ee; u16 min_apid; u16 max_apid; - u16 max_periph; u32 *mapping_table; DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS); struct irq_domain *domain; @@ -164,7 +162,6 @@ struct spmi_pmic_arb { * * @ver_str: version string. * @ppid_to_apid: finds the apid for a given ppid. - * @mode: access rights to specified pmic peripheral. * @non_data_cmd: on v1 issues an spmi non-data command. * on v2 no HW support, returns -EOPNOTSUPP. * @offset:on v1 offset of per-ee channel. @@ -183,8 +180,6 @@ struct pmic_arb_ver_ops { const char *ver_str; int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid); - int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, - mode_t *mode); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, u32 *offset); @@ -340,23 +335,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u32 cmd; int rc; u32 offset; - mode_t mode; rc = pa->ver_ops->offset(pa, sid, addr, &offset); if (rc) return rc; - rc = pa->ver_ops->mode(pa, sid, addr, &mode); - if (rc) - return rc; - - if (!(mode & S_IRUSR)) { - dev_err(&pa->spmic->dev, - "error: impermissible read from peripheral sid:%d addr:0x%x\n", - sid, addr); - return -EPERM; - } - if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", @@ -402,23 +385,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u32 cmd; int rc; u32 offset; - mode_t mode; rc = pa->ver_ops->offset(pa, sid, addr, &offset); if (rc) return rc; - rc = pa->ver_ops->mode(pa, sid, addr, &mode); - if (rc) - return rc; - - if (!(mode & S_IWUSR)) { - dev_err(&pa->spmic->dev, - "error: impermissible write to peripheral sid:%d addr:0x%x\n", - sid, addr); - return -EPERM; - } - if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", @@ -785,13 +756,6 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, return -ENODEV; } -static int -pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) -{ - *mode = S_IRUSR | S_IWUSR; - return 0; -} - /* v1 offset per ee */ static int pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) @@ -810,15 +774,15 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. * ppid_to_apid is an in-memory invert of that table. */ - for (apid = pa->last_apid; apid < pa->max_periph; apid++) { - regval = readl_relaxed(pa->cnfg + - SPMI_OWNERSHIP_TABLE_REG(apid)); - pa->apid_data[a
[PATCH V2 02/12] spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other cleanup
This patch cleans up the following. - Rename the "pa" to "pmic_arb". - Rename the spmi_pmic_arb *dev to spmi_pmic_arb *pmic_arb. - Rename the pa_{read,write}_data() functions to pmic_arb_{read,write}_data(). - Rename channel to APID. - Rename the HWIRQ_*() macros to hwirq_to_*(). Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 418 +-- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 7531519..530fa11 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -39,7 +39,7 @@ #define PMIC_ARB_WDATA10x14 #define PMIC_ARB_RDATA00x18 #define PMIC_ARB_RDATA10x1C -#define PMIC_ARB_REG_CHNL(N) (0x800 + 0x4 * (N)) +#define PMIC_ARB_REG_APID(N) (0x800 + 0x4 * (N)) /* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) @@ -51,7 +51,7 @@ #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ -#define PMIC_ARB_CHAN_VALIDBIT(15) +#define PMIC_ARB_APID_VALIDBIT(15) /* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N))) @@ -97,16 +97,16 @@ enum pmic_arb_cmd_op_code { /* interrupt enable bit */ #define SPMI_PIC_ACC_ENABLE_BITBIT(0) -#define HWIRQ(slave_id, periph_id, irq_id, apid) \ +#define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ slave_id) & 0xF) << 28) | \ (((periph_id) & 0xFF) << 20) | \ (((irq_id)& 0x7) << 16) | \ (((apid) & 0x1FF) << 0)) -#define HWIRQ_SID(hwirq) (((hwirq) >> 28) & 0xF) -#define HWIRQ_PER(hwirq) (((hwirq) >> 20) & 0xFF) -#define HWIRQ_IRQ(hwirq) (((hwirq) >> 16) & 0x7) -#define HWIRQ_APID(hwirq) (((hwirq) >> 0) & 0x1FF) +#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) +#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) +#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) +#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF) struct pmic_arb_ver_ops; @@ -132,7 +132,7 @@ struct apid_data { * @domain:irq domain object for PMIC IRQ domain * @spmic: SPMI controller object * @ver_ops: version dependent operations. - * @ppid_to_apid in-memory copy of PPID -> channel (APID) mapping table. + * @ppid_to_apid in-memory copy of PPID -> APID mapping table. */ struct spmi_pmic_arb { void __iomem*rd_base; @@ -178,10 +178,10 @@ struct spmi_pmic_arb { */ struct pmic_arb_ver_ops { const char *ver_str; - int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, + int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, u16 *apid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, u32 *offset); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); @@ -192,56 +192,57 @@ struct pmic_arb_ver_ops { u32 (*irq_clear)(u16 n); }; -static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa, +static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, u32 offset, u32 val) { - writel_relaxed(val, pa->wr_base + offset); + writel_relaxed(val, pmic_arb->wr_base + offset); } -static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa, +static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb, u32 offset, u32 val) { - writel_relaxed(val, pa->rd_base + offset); + writel_relaxed(val, pmic_arb->rd_base + offset); } /** - * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf + * pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf * @bc:byte count -1. range: 0..3 * @reg: register's address * @buf: output parameter, length must be bc + 1 */ -static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc) +static void +pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc) { - u32 data = __raw_readl(pa->rd_base + reg); + u32 data = __raw_readl(pmic_arb->rd_base + reg); memcpy(buf, &data, (bc & 3) + 1); } /** - * pa_write_data: write 1..4 bytes from buf to pmic-arb's register + * pmic_arb_write_data: write 1..4 bytes from buf to pmic
[PATCH V2 03/12] spmi: pmic-arb: clean up pmic_arb_find_apid function
Clean up the pmic_arb_find_apid() by using the local variables to improve the code readability. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 530fa11..530d410 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -762,23 +762,22 @@ static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid) { + struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid]; u32 regval, offset; - u16 apid; - u16 id; + u16 id, apid; /* -* PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. +* PMIC_ARB_REG_APID is a table in HW mapping apid to ppid. * ppid_to_apid is an in-memory invert of that table. */ - for (apid = pmic_arb->last_apid; ; apid++) { + for (apid = pmic_arb->last_apid; ; apid++, apidd++) { offset = PMIC_ARB_REG_APID(apid); if (offset >= pmic_arb->core_size) break; regval = readl_relaxed(pmic_arb->cnfg + SPMI_OWNERSHIP_TABLE_REG(apid)); - pmic_arb->apid_data[apid].owner = - SPMI_OWNERSHIP_PERIPH2OWNER(regval); + apidd->owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval); regval = readl_relaxed(pmic_arb->core + offset); if (!regval) @@ -786,7 +785,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid) id = (regval >> 8) & PMIC_ARB_PPID_MASK; pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID; - pmic_arb->apid_data[apid].ppid = id; + apidd->ppid = id; if (id == ppid) { apid |= PMIC_ARB_APID_VALID; break; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 06/12] spmi: pmic-arb: replace the writel_relaxed with __raw_writel
Replace the writel_relaxed with __raw_writel to avoid byte swapping in pmic_arb_write_data() function. That way the code is independent of the CPU endianness. Fixes: 111a10bf3e53 ("spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb") Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 340e7b8..a9d9359 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -230,7 +230,7 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, u32 data = 0; memcpy(&data, buf, (bc & 3) + 1); - pmic_arb_base_write(pmic_arb, reg, data); + __raw_writel(data, pmic_arb->wr_base + reg); } static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 04/12] spmi: pmic-arb: optimize qpnpint_irq_set_type function
Optimize the qpnpint_irq_set_type() by using a local variable to hold the handler type. Also clean up other variable usage. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 24 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 530d410..0577cfd 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -587,35 +587,35 @@ static void qpnpint_irq_unmask(struct irq_data *d) static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) { struct spmi_pmic_arb_qpnpint_type type; + irq_flow_handler_t flow_handler; u8 irq = hwirq_to_irq(d->hwirq); - u8 bit_mask_irq = BIT(irq); qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { - type.type |= bit_mask_irq; + type.type |= BIT(irq); if (flow_type & IRQF_TRIGGER_RISING) - type.polarity_high |= bit_mask_irq; + type.polarity_high |= BIT(irq); if (flow_type & IRQF_TRIGGER_FALLING) - type.polarity_low |= bit_mask_irq; + type.polarity_low |= BIT(irq); + + flow_handler = handle_edge_irq; } else { if ((flow_type & (IRQF_TRIGGER_HIGH)) && (flow_type & (IRQF_TRIGGER_LOW))) return -EINVAL; - type.type &= ~bit_mask_irq; /* level trig */ + type.type &= ~BIT(irq); /* level trig */ if (flow_type & IRQF_TRIGGER_HIGH) - type.polarity_high |= bit_mask_irq; + type.polarity_high |= BIT(irq); else - type.polarity_low |= bit_mask_irq; + type.polarity_low |= BIT(irq); + + flow_handler = handle_level_irq; } qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); - - if (flow_type & IRQ_TYPE_EDGE_BOTH) - irq_set_handler_locked(d, handle_edge_irq); - else - irq_set_handler_locked(d, handle_level_irq); + irq_set_handler_locked(d, flow_handler); return 0; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 08/12] spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability
Currently the driver sets the pmic arbiter core interrupt as wakeup capable irrespective of the child irqs which causes the system to wakeup unnecessarily. To fix this, set the core interrupt as wakeup capable only if any of the child irqs request for it. Do this by marking it as wakeup capable in the irq_set_wake callback. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 2f9875a..f8900d3 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -622,6 +622,13 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) return 0; } +static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); + + return irq_set_irq_wake(pmic_arb->irq, on); +} + static int qpnpint_get_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool *state) @@ -644,9 +651,9 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, .irq_mask = qpnpint_irq_mask, .irq_unmask = qpnpint_irq_unmask, .irq_set_type = qpnpint_irq_set_type, + .irq_set_wake = qpnpint_irq_set_wake, .irq_get_irqchip_state = qpnpint_get_irqchip_state, - .flags = IRQCHIP_MASK_ON_SUSPEND - | IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, @@ -1068,8 +1075,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq, pmic_arb); - enable_irq_wake(pmic_arb->irq); - err = spmi_controller_add(ctrl); if (err) goto err_domain_remove; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 12/12] spmi: pmic-arb: Remove checking opc value not less than 0
From: Fenglin Wu The opc parameter in pmic_arb_write_cmd() function is defined with type u8 and it's always greater than or equal to 0. Checking that it's not less than 0 is redundant and it can cause a forbidden warning during compilation. Remove the check. Signed-off-by: Fenglin Wu Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 3f46445..ca9bdd3 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017, 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 @@ -419,7 +419,7 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, /* Check the opcode */ if (opc >= 0x40 && opc <= 0x5F) opc = PMIC_ARB_OP_WRITE; - else if (opc >= 0x00 && opc <= 0x0F) + else if (opc <= 0x0F) opc = PMIC_ARB_OP_EXT_WRITE; else if (opc >= 0x30 && opc <= 0x37) opc = PMIC_ARB_OP_EXT_WRITEL; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 11/12] spmi: pmic-arb: add support for HW version 5
From: David Collins Add support for version 5 of the SPMI PMIC arbiter. It utilizes different offsets for registers than those found on version 3. Also, the procedure to determine if writing and IRQ access is allowed for a given PPID changes for version 5. Signed-off-by: David Collins Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 236 +++ 1 file changed, 214 insertions(+), 22 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index bc68e08..3f46445 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -29,6 +29,7 @@ #define PMIC_ARB_VERSION 0x #define PMIC_ARB_VERSION_V2_MIN0x2001 #define PMIC_ARB_VERSION_V3_MIN0x3000 +#define PMIC_ARB_VERSION_V5_MIN0x5000 #define PMIC_ARB_INT_EN0x0004 /* PMIC Arbiter channel registers offsets */ @@ -39,7 +40,6 @@ #define PMIC_ARB_WDATA10x14 #define PMIC_ARB_RDATA00x18 #define PMIC_ARB_RDATA10x1C -#define PMIC_ARB_REG_APID(N) (0x800 + 0x4 * (N)) /* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) @@ -52,6 +52,8 @@ #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ #define PMIC_ARB_APID_VALIDBIT(15) +#define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg)((reg) & BIT(24)) +#define INVALID_EE 0xFF /* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N))) @@ -86,6 +88,15 @@ enum pmic_arb_cmd_op_code { PMIC_ARB_OP_ZERO_WRITE = 16, }; +/* + * PMIC arbiter version 5 uses different register offsets for read/write vs + * observer channels. + */ +enum pmic_arb_channel { + PMIC_ARB_CHANNEL_RW, + PMIC_ARB_CHANNEL_OBS, +}; + /* Maximum number of support PMIC peripherals */ #define PMIC_ARB_MAX_PERIPHS 512 #define PMIC_ARB_TIMEOUT_US100 @@ -112,7 +123,8 @@ enum pmic_arb_cmd_op_code { struct apid_data { u16 ppid; - u8 owner; + u8 write_ee; + u8 irq_ee; }; /** @@ -175,12 +187,14 @@ struct spmi_pmic_arb { * on v2 address of SPMI_PIC_IRQ_STATUSn. * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn * on v2 address of SPMI_PIC_IRQ_CLEARn. + * @apid_map_offset: offset of PMIC_ARB_REG_CHNLn */ struct pmic_arb_ver_ops { const char *ver_str; int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr); + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, + enum pmic_arb_channel ch_type); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ @@ -189,6 +203,7 @@ struct pmic_arb_ver_ops { void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); + u32 (*apid_map_offset)(u16 n); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -233,7 +248,8 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, } static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, - void __iomem *base, u8 sid, u16 addr) + void __iomem *base, u8 sid, u16 addr, + enum pmic_arb_channel ch_type) { struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); u32 status = 0; @@ -241,7 +257,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, u32 offset; int rc; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type); if (rc < 0) return rc; @@ -289,7 +305,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW); if (rc < 0) return rc; @@ -298,7 +314,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb
[PATCH V2 00/12]: spmi: pmic-arb: Support for HW v5 and other fixes
v2: * [PATCH V2 04/12] spmi: pmic-arb: optimize qpnpint_irq_set_type function Added Stephen's Reviewed-by tag. * [PATCH V2 05/12] spmi: pmic-arb: fix memory allocation for mapping_table Added Fixes tag and Stephen's Reviewed-by tag. * [PATCH V2 02/12] spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other cleanup Added Stephen's Reviewed-by tag. * [PATCH V2 06/12] spmi: pmic-arb: replace the writel_relaxed with __raw_writel Added Fixes tag. * [PATCH V2 03/12] spmi: pmic-arb: clean up pmic_arb_find_apid function Fixed alignement issue and added Stephen's reviewed-by tag. Now all the patches in this series are reviewed and acked by Stephen boyd and are ready for merge. v1: * This patch series add the support for pmic arbiter hardware v5 along with the few bug fixes and code cleanup. * This new series is the combined series of [PATCH V3 0/5]: spmi: pmic-arb: Fixup patches and [PATCH V4 0/4]: spmi: pmic-arb: support for V5 HW and bug fixes, which are being reviewed by Stephen Boyd. * This series depends on the below patch uploaded by Stephen Boyd https://patchwork.kernel.org/patch/9810723/. David Collins (1): spmi: pmic-arb: add support for HW version 5 Fenglin Wu (1): spmi: pmic-arb: Remove checking opc value not less than 0 Kiran Gunda (10): spmi: pmic-arb: remove the read/write access checks spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other cleanup spmi: pmic-arb: clean up pmic_arb_find_apid function spmi: pmic-arb: optimize qpnpint_irq_set_type function spmi: pmic-arb: fix memory allocation for mapping_table spmi: pmic-arb: replace the writel_relaxed with __raw_writel spmi: pmic-arb: return the value instead of passing by pointer spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability spmi: pmic-arb: return __iomem pointer instead of offset spmi: pmic-arb: fix a possible null pointer dereference drivers/spmi/spmi-pmic-arb.c | 825 +-- 1 file changed, 481 insertions(+), 344 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 05/12] spmi: pmic-arb: fix memory allocation for mapping_table
Allocate the correct memory size (max_pmic_peripherals) for the mapping_table that holds the apid to ppid mapping. Also use a local variable for mapping_table for better alignment of the code. Fixes: 987a9f128b8a ("spmi: pmic-arb: Support more than 128 peripherals") Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 11 +-- 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 0577cfd..340e7b8 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -929,6 +929,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) struct spmi_controller *ctrl; struct resource *res; void __iomem *core; + u32 *mapping_table; u32 channel, ee, hw_ver; int err; @@ -1038,16 +1039,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) } pmic_arb->ee = ee; - - pmic_arb->mapping_table = devm_kcalloc(&ctrl->dev, - PMIC_ARB_MAX_PERIPHS - 1, - sizeof(*pmic_arb->mapping_table), - GFP_KERNEL); - if (!pmic_arb->mapping_table) { + mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS, + sizeof(*mapping_table), GFP_KERNEL); + if (!mapping_table) { err = -ENOMEM; goto err_put_ctrl; } + pmic_arb->mapping_table = mapping_table; /* Initialize max_apid/min_apid to the opposite bounds, during * the irq domain translation, we are sure to update these */ pmic_arb->max_apid = 0; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 07/12] spmi: pmic-arb: return the value instead of passing by pointer
Returning the output value from a function, when it is possible, is the better and cleaner way than passing it by the pointer. Hence, modify the ppid_to_apid mapping function to return apid instead of passing it by a pointer. While at it, pass the ppid as function parameter to ppid_to_apid mapping function instead of passing the sid and addr. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 82 +--- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index a9d9359..2f9875a 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -178,11 +178,9 @@ struct spmi_pmic_arb { */ struct pmic_arb_ver_ops { const char *ver_str; - int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, - u16 *apid); + int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, - u32 *offset); + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ @@ -242,10 +240,11 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, u32 offset; int rc; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; offset += PMIC_ARB_STATUS; while (timeout--) { @@ -289,10 +288,11 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); + if (rc < 0) return rc; + offset = rc; cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); raw_spin_lock_irqsave(&pmic_arb->lock, flags); @@ -333,10 +333,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); @@ -383,10 +384,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); @@ -655,8 +657,8 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, unsigned int *out_type) { struct spmi_pmic_arb *pmic_arb = d->host_data; + u16 apid, ppid; int rc; - u16 apid; dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", intspec[0], intspec[1], intspec[2]); @@ -668,14 +670,15 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) return -EINVAL; - rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, intspec[0], - (intspec[1] << 8), &apid); + ppid = intspec[0] << 8 | intspec[1]; + rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid); if (rc < 0) { dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n", intspec[0], intspec[1], intspec[2], rc); return rc; } + apid = rc; /* Keep track of {max,min}_apid for bounding search during interrupt */ if (apid > pmic_arb->max_apid) pmic_arb->max_apid = apid; @@ -704,19 +707,18 @@ static int qpnpint_irq_domain_map(struc
[PATCH V2 10/12] spmi: pmic-arb: fix a possible null pointer dereference
If "core" memory resource is not specified, then the driver could end up dereferencing a null pointer. Fix this issue. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 88fe421..bc68e08 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -955,14 +955,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pmic_arb->spmic = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); - pmic_arb->core_size = resource_size(res); - core = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(core)) { err = PTR_ERR(core); goto err_put_ctrl; } + pmic_arb->core_size = resource_size(res); + pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, sizeof(*pmic_arb->ppid_to_apid), GFP_KERNEL); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V2 09/12] spmi: pmic-arb: return __iomem pointer instead of offset
Modify the pmic_arb version ops to return an __iomem pointer to the address instead of an offset. That way we do not need to care about the base address changes in the new HW version. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 93 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index f8900d3..88fe421 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -167,14 +167,14 @@ struct spmi_pmic_arb { * @offset:on v1 offset of per-ee channel. * on v2 offset of per-ee and per-ppid channel. * @fmt_cmd: formats a GENI/SPMI command. - * @owner_acc_status: on v1 offset of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn - * on v2 offset of SPMI_PIC_OWNERm_ACC_STATUSn. - * @acc_enable:on v1 offset of PMIC_ARB_SPMI_PIC_ACC_ENABLEn - * on v2 offset of SPMI_PIC_ACC_ENABLEn. - * @irq_status:on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_STATUSn - * on v2 offset of SPMI_PIC_IRQ_STATUSn. - * @irq_clear: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_CLEARn - * on v2 offset of SPMI_PIC_IRQ_CLEARn. + * @owner_acc_status: on v1 address of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn + * on v2 address of SPMI_PIC_OWNERm_ACC_STATUSn. + * @acc_enable:on v1 address of PMIC_ARB_SPMI_PIC_ACC_ENABLEn + * on v2 address of SPMI_PIC_ACC_ENABLEn. + * @irq_status:on v1 address of PMIC_ARB_SPMI_PIC_IRQ_STATUSn + * on v2 address of SPMI_PIC_IRQ_STATUSn. + * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn + * on v2 address of SPMI_PIC_IRQ_CLEARn. */ struct pmic_arb_ver_ops { const char *ver_str; @@ -184,10 +184,11 @@ struct pmic_arb_ver_ops { u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ - u32 (*owner_acc_status)(u8 m, u16 n); - u32 (*acc_enable)(u16 n); - u32 (*irq_status)(u16 n); - u32 (*irq_clear)(u16 n); + void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m, + u16 n); + void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); + void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); + void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -475,8 +476,7 @@ static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id) u8 per = ppid & 0xFF; u8 irq_mask = BIT(id); - writel_relaxed(irq_mask, pmic_arb->intr + - pmic_arb->ver_ops->irq_clear(apid)); + writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid)); if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1)) @@ -497,8 +497,7 @@ static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF; u8 per = pmic_arb->apid_data[apid].ppid & 0xFF; - status = readl_relaxed(pmic_arb->intr + - pmic_arb->ver_ops->irq_status(apid)); + status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid)); while (status) { id = ffs(status) - 1; status &= ~BIT(id); @@ -515,24 +514,25 @@ static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) static void pmic_arb_chained_irq(struct irq_desc *desc) { struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc); + const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; struct irq_chip *chip = irq_desc_get_chip(desc); - void __iomem *intr = pmic_arb->intr; int first = pmic_arb->min_apid >> 5; int last = pmic_arb->max_apid >> 5; + u8 ee = pmic_arb->ee; u32 status, enable; int i, id, apid; chained_irq_enter(chip, desc); for (i = first; i <= last; ++i) { - status = readl_relaxed(intr + -pmic_arb->ver_ops->owner_acc_status(pmic_arb->ee, i)); + status = readl_relaxed( + ver_ops->owner_acc_status(pmic_arb, ee, i)); while (status) { id = ffs(status) - 1; status &= ~BIT(id); apid = id + i * 32; -
[PATCH V1 03/12] spmi: pmic-arb: clean up pmic_arb_find_apid function
Clean up the pmic_arb_find_apid() by using the local variables to improve the code readability. Signed-off-by: Kiran Gunda --- drivers/spmi/spmi-pmic-arb.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 530fa11..cd78665 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -762,23 +762,22 @@ static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid) { + struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid]; u32 regval, offset; - u16 apid; - u16 id; + u16 id, apid; /* -* PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. +* PMIC_ARB_REG_APID is a table in HW mapping apid to ppid. * ppid_to_apid is an in-memory invert of that table. */ - for (apid = pmic_arb->last_apid; ; apid++) { + for (apid = pmic_arb->last_apid; ; apid++, apidd++) { offset = PMIC_ARB_REG_APID(apid); if (offset >= pmic_arb->core_size) break; regval = readl_relaxed(pmic_arb->cnfg + - SPMI_OWNERSHIP_TABLE_REG(apid)); - pmic_arb->apid_data[apid].owner = - SPMI_OWNERSHIP_PERIPH2OWNER(regval); + SPMI_OWNERSHIP_TABLE_REG(apid)); + apidd->owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval); regval = readl_relaxed(pmic_arb->core + offset); if (!regval) @@ -786,7 +785,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid) id = (regval >> 8) & PMIC_ARB_PPID_MASK; pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID; - pmic_arb->apid_data[apid].ppid = id; + apidd->ppid = id; if (id == ppid) { apid |= PMIC_ARB_APID_VALID; break; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 05/12] spmi: pmic-arb: fix memory allocation for mapping_table
Allocate the correct memory size (max_pmic_peripherals) for the mapping_table that holds the apid to ppid mapping. Also use a local variable for mapping_table for better alignment of the code. Signed-off-by: Kiran Gunda --- drivers/spmi/spmi-pmic-arb.c | 11 +-- 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 0c98495..b32b5b0 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -929,6 +929,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) struct spmi_controller *ctrl; struct resource *res; void __iomem *core; + u32 *mapping_table; u32 channel, ee, hw_ver; int err; @@ -1038,16 +1039,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) } pmic_arb->ee = ee; - - pmic_arb->mapping_table = devm_kcalloc(&ctrl->dev, - PMIC_ARB_MAX_PERIPHS - 1, - sizeof(*pmic_arb->mapping_table), - GFP_KERNEL); - if (!pmic_arb->mapping_table) { + mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS, + sizeof(*mapping_table), GFP_KERNEL); + if (!mapping_table) { err = -ENOMEM; goto err_put_ctrl; } + pmic_arb->mapping_table = mapping_table; /* Initialize max_apid/min_apid to the opposite bounds, during * the irq domain translation, we are sure to update these */ pmic_arb->max_apid = 0; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 07/12] spmi: pmic-arb: return the value instead of passing by pointer
Returning the output value from a function, when it is possible, is the better and cleaner way than passing it by the pointer. Hence, modify the ppid_to_apid mapping function to return apid instead of passing it by a pointer. While at it, pass the ppid as function parameter to ppid_to_apid mapping function instead of passing the sid and addr. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 82 +--- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index a18ff99..fed2883a 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -178,11 +178,9 @@ struct spmi_pmic_arb { */ struct pmic_arb_ver_ops { const char *ver_str; - int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, - u16 *apid); + int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, - u32 *offset); + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ @@ -242,10 +240,11 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, u32 offset; int rc; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; offset += PMIC_ARB_STATUS; while (timeout--) { @@ -289,10 +288,11 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); + if (rc < 0) return rc; + offset = rc; cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); raw_spin_lock_irqsave(&pmic_arb->lock, flags); @@ -333,10 +333,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); @@ -383,10 +384,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); @@ -655,8 +657,8 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, unsigned int *out_type) { struct spmi_pmic_arb *pmic_arb = d->host_data; + u16 apid, ppid; int rc; - u16 apid; dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", intspec[0], intspec[1], intspec[2]); @@ -668,14 +670,15 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) return -EINVAL; - rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, intspec[0], - (intspec[1] << 8), &apid); + ppid = intspec[0] << 8 | intspec[1]; + rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid); if (rc < 0) { dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n", intspec[0], intspec[1], intspec[2], rc); return rc; } + apid = rc; /* Keep track of {max,min}_apid for bounding search during interrupt */ if (apid > pmic_arb->max_apid) pmic_arb->max_apid = apid; @@ -704,19 +707,18 @@ static int qpnpint_irq_domain_map(struc
[PATCH V1 09/12] spmi: pmic-arb: return __iomem pointer instead of offset
Modify the pmic_arb version ops to return an __iomem pointer to the address instead of an offset. That way we do not need to care about the base address changes in the new HW version. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 93 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index e8c08c0..d997449 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -167,14 +167,14 @@ struct spmi_pmic_arb { * @offset:on v1 offset of per-ee channel. * on v2 offset of per-ee and per-ppid channel. * @fmt_cmd: formats a GENI/SPMI command. - * @owner_acc_status: on v1 offset of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn - * on v2 offset of SPMI_PIC_OWNERm_ACC_STATUSn. - * @acc_enable:on v1 offset of PMIC_ARB_SPMI_PIC_ACC_ENABLEn - * on v2 offset of SPMI_PIC_ACC_ENABLEn. - * @irq_status:on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_STATUSn - * on v2 offset of SPMI_PIC_IRQ_STATUSn. - * @irq_clear: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_CLEARn - * on v2 offset of SPMI_PIC_IRQ_CLEARn. + * @owner_acc_status: on v1 address of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn + * on v2 address of SPMI_PIC_OWNERm_ACC_STATUSn. + * @acc_enable:on v1 address of PMIC_ARB_SPMI_PIC_ACC_ENABLEn + * on v2 address of SPMI_PIC_ACC_ENABLEn. + * @irq_status:on v1 address of PMIC_ARB_SPMI_PIC_IRQ_STATUSn + * on v2 address of SPMI_PIC_IRQ_STATUSn. + * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn + * on v2 address of SPMI_PIC_IRQ_CLEARn. */ struct pmic_arb_ver_ops { const char *ver_str; @@ -184,10 +184,11 @@ struct pmic_arb_ver_ops { u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ - u32 (*owner_acc_status)(u8 m, u16 n); - u32 (*acc_enable)(u16 n); - u32 (*irq_status)(u16 n); - u32 (*irq_clear)(u16 n); + void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m, + u16 n); + void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); + void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); + void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -475,8 +476,7 @@ static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id) u8 per = ppid & 0xFF; u8 irq_mask = BIT(id); - writel_relaxed(irq_mask, pmic_arb->intr + - pmic_arb->ver_ops->irq_clear(apid)); + writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid)); if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1)) @@ -497,8 +497,7 @@ static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF; u8 per = pmic_arb->apid_data[apid].ppid & 0xFF; - status = readl_relaxed(pmic_arb->intr + - pmic_arb->ver_ops->irq_status(apid)); + status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid)); while (status) { id = ffs(status) - 1; status &= ~BIT(id); @@ -515,24 +514,25 @@ static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) static void pmic_arb_chained_irq(struct irq_desc *desc) { struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc); + const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; struct irq_chip *chip = irq_desc_get_chip(desc); - void __iomem *intr = pmic_arb->intr; int first = pmic_arb->min_apid >> 5; int last = pmic_arb->max_apid >> 5; + u8 ee = pmic_arb->ee; u32 status, enable; int i, id, apid; chained_irq_enter(chip, desc); for (i = first; i <= last; ++i) { - status = readl_relaxed(intr + -pmic_arb->ver_ops->owner_acc_status(pmic_arb->ee, i)); + status = readl_relaxed( + ver_ops->owner_acc_status(pmic_arb, ee, i)); while (status) { id = ffs(status) - 1; status &= ~BIT(id); apid = id + i * 32; -
[PATCH V1 12/12] spmi: pmic-arb: Remove checking opc value not less than 0
From: Fenglin Wu The opc parameter in pmic_arb_write_cmd() function is defined with type u8 and it's always greater than or equal to 0. Checking that it's not less than 0 is redundant and it can cause a forbidden warning during compilation. Remove the check. Signed-off-by: Fenglin Wu Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 01559d7..8ab3f6d 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017, 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 @@ -419,7 +419,7 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, /* Check the opcode */ if (opc >= 0x40 && opc <= 0x5F) opc = PMIC_ARB_OP_WRITE; - else if (opc >= 0x00 && opc <= 0x0F) + else if (opc <= 0x0F) opc = PMIC_ARB_OP_EXT_WRITE; else if (opc >= 0x30 && opc <= 0x37) opc = PMIC_ARB_OP_EXT_WRITEL; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 08/12] spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability
Currently the driver sets the pmic arbiter core interrupt as wakeup capable irrespective of the child irqs which causes the system to wakeup unnecessarily. To fix this, set the core interrupt as wakeup capable only if any of the child irqs request for it. Do this by marking it as wakeup capable in the irq_set_wake callback. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index fed2883a..e8c08c0 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -622,6 +622,13 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) return 0; } +static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); + + return irq_set_irq_wake(pmic_arb->irq, on); +} + static int qpnpint_get_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool *state) @@ -644,9 +651,9 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, .irq_mask = qpnpint_irq_mask, .irq_unmask = qpnpint_irq_unmask, .irq_set_type = qpnpint_irq_set_type, + .irq_set_wake = qpnpint_irq_set_wake, .irq_get_irqchip_state = qpnpint_get_irqchip_state, - .flags = IRQCHIP_MASK_ON_SUSPEND - | IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, @@ -1068,8 +1075,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq, pmic_arb); - enable_irq_wake(pmic_arb->irq); - err = spmi_controller_add(ctrl); if (err) goto err_domain_remove; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 11/12] spmi: pmic-arb: add support for HW version 5
From: David Collins Add support for version 5 of the SPMI PMIC arbiter. It utilizes different offsets for registers than those found on version 3. Also, the procedure to determine if writing and IRQ access is allowed for a given PPID changes for version 5. Signed-off-by: David Collins Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 236 +++ 1 file changed, 214 insertions(+), 22 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index c585e06..01559d7 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -29,6 +29,7 @@ #define PMIC_ARB_VERSION 0x #define PMIC_ARB_VERSION_V2_MIN0x2001 #define PMIC_ARB_VERSION_V3_MIN0x3000 +#define PMIC_ARB_VERSION_V5_MIN0x5000 #define PMIC_ARB_INT_EN0x0004 /* PMIC Arbiter channel registers offsets */ @@ -39,7 +40,6 @@ #define PMIC_ARB_WDATA10x14 #define PMIC_ARB_RDATA00x18 #define PMIC_ARB_RDATA10x1C -#define PMIC_ARB_REG_APID(N) (0x800 + 0x4 * (N)) /* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) @@ -52,6 +52,8 @@ #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ #define PMIC_ARB_APID_VALIDBIT(15) +#define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg)((reg) & BIT(24)) +#define INVALID_EE 0xFF /* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N))) @@ -86,6 +88,15 @@ enum pmic_arb_cmd_op_code { PMIC_ARB_OP_ZERO_WRITE = 16, }; +/* + * PMIC arbiter version 5 uses different register offsets for read/write vs + * observer channels. + */ +enum pmic_arb_channel { + PMIC_ARB_CHANNEL_RW, + PMIC_ARB_CHANNEL_OBS, +}; + /* Maximum number of support PMIC peripherals */ #define PMIC_ARB_MAX_PERIPHS 512 #define PMIC_ARB_TIMEOUT_US100 @@ -112,7 +123,8 @@ enum pmic_arb_cmd_op_code { struct apid_data { u16 ppid; - u8 owner; + u8 write_ee; + u8 irq_ee; }; /** @@ -175,12 +187,14 @@ struct spmi_pmic_arb { * on v2 address of SPMI_PIC_IRQ_STATUSn. * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn * on v2 address of SPMI_PIC_IRQ_CLEARn. + * @apid_map_offset: offset of PMIC_ARB_REG_CHNLn */ struct pmic_arb_ver_ops { const char *ver_str; int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr); + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, + enum pmic_arb_channel ch_type); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ @@ -189,6 +203,7 @@ struct pmic_arb_ver_ops { void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); + u32 (*apid_map_offset)(u16 n); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -233,7 +248,8 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, } static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, - void __iomem *base, u8 sid, u16 addr) + void __iomem *base, u8 sid, u16 addr, + enum pmic_arb_channel ch_type) { struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); u32 status = 0; @@ -241,7 +257,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, u32 offset; int rc; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type); if (rc < 0) return rc; @@ -289,7 +305,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW); if (rc < 0) return rc; @@ -298,7 +314,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb
[PATCH V1 10/12] spmi: pmic-arb: fix a possible null pointer dereference
If "core" memory resource is not specified, then the driver could end up dereferencing a null pointer. Fix this issue. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index d997449..c585e06 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -955,14 +955,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pmic_arb->spmic = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); - pmic_arb->core_size = resource_size(res); - core = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(core)) { err = PTR_ERR(core); goto err_put_ctrl; } + pmic_arb->core_size = resource_size(res); + pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, sizeof(*pmic_arb->ppid_to_apid), GFP_KERNEL); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 04/12] spmi: pmic-arb: optimize qpnpint_irq_set_type function
Optimize the qpnpint_irq_set_type() by using a local variable to hold the handler type. Also clean up other variable usage. Signed-off-by: Kiran Gunda --- drivers/spmi/spmi-pmic-arb.c | 24 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index cd78665..0c98495 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -587,35 +587,35 @@ static void qpnpint_irq_unmask(struct irq_data *d) static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) { struct spmi_pmic_arb_qpnpint_type type; + irq_flow_handler_t flow_handler; u8 irq = hwirq_to_irq(d->hwirq); - u8 bit_mask_irq = BIT(irq); qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { - type.type |= bit_mask_irq; + type.type |= BIT(irq); if (flow_type & IRQF_TRIGGER_RISING) - type.polarity_high |= bit_mask_irq; + type.polarity_high |= BIT(irq); if (flow_type & IRQF_TRIGGER_FALLING) - type.polarity_low |= bit_mask_irq; + type.polarity_low |= BIT(irq); + + flow_handler = handle_edge_irq; } else { if ((flow_type & (IRQF_TRIGGER_HIGH)) && (flow_type & (IRQF_TRIGGER_LOW))) return -EINVAL; - type.type &= ~bit_mask_irq; /* level trig */ + type.type &= ~BIT(irq); /* level trig */ if (flow_type & IRQF_TRIGGER_HIGH) - type.polarity_high |= bit_mask_irq; + type.polarity_high |= BIT(irq); else - type.polarity_low |= bit_mask_irq; + type.polarity_low |= BIT(irq); + + flow_handler = handle_level_irq; } qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); - - if (flow_type & IRQ_TYPE_EDGE_BOTH) - irq_set_handler_locked(d, handle_edge_irq); - else - irq_set_handler_locked(d, handle_level_irq); + irq_set_handler_locked(d, flow_handler); return 0; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 01/12] spmi: pmic-arb: remove the read/write access checks
The access mode checks for peripheral ownership for read/write permissions should not be required. Every peripheral enabled for this master is expected to have a read/write permissions. If there is any such invalid access due to wrong configuration in boot loader or device tree files, then it should be fixed in those locations. Hence, remove the access mode checks from the driver. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 75 +++- 1 file changed, 5 insertions(+), 70 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index f4b7a98..7531519 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -128,7 +128,6 @@ struct apid_data { * @ee:the current Execution Environment * @min_apid: minimum APID (used for bounding IRQ search) * @max_apid: maximum APID - * @max_periph:maximum number of PMIC peripherals supported by HW. * @mapping_table: in-memory copy of PPID -> APID mapping table. * @domain:irq domain object for PMIC IRQ domain * @spmic: SPMI controller object @@ -148,7 +147,6 @@ struct spmi_pmic_arb { u8 ee; u16 min_apid; u16 max_apid; - u16 max_periph; u32 *mapping_table; DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS); struct irq_domain *domain; @@ -164,7 +162,6 @@ struct spmi_pmic_arb { * * @ver_str: version string. * @ppid_to_apid: finds the apid for a given ppid. - * @mode: access rights to specified pmic peripheral. * @non_data_cmd: on v1 issues an spmi non-data command. * on v2 no HW support, returns -EOPNOTSUPP. * @offset:on v1 offset of per-ee channel. @@ -183,8 +180,6 @@ struct pmic_arb_ver_ops { const char *ver_str; int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid); - int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, - mode_t *mode); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, u32 *offset); @@ -340,23 +335,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u32 cmd; int rc; u32 offset; - mode_t mode; rc = pa->ver_ops->offset(pa, sid, addr, &offset); if (rc) return rc; - rc = pa->ver_ops->mode(pa, sid, addr, &mode); - if (rc) - return rc; - - if (!(mode & S_IRUSR)) { - dev_err(&pa->spmic->dev, - "error: impermissible read from peripheral sid:%d addr:0x%x\n", - sid, addr); - return -EPERM; - } - if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", @@ -402,23 +385,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u32 cmd; int rc; u32 offset; - mode_t mode; rc = pa->ver_ops->offset(pa, sid, addr, &offset); if (rc) return rc; - rc = pa->ver_ops->mode(pa, sid, addr, &mode); - if (rc) - return rc; - - if (!(mode & S_IWUSR)) { - dev_err(&pa->spmic->dev, - "error: impermissible write to peripheral sid:%d addr:0x%x\n", - sid, addr); - return -EPERM; - } - if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", @@ -785,13 +756,6 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, return -ENODEV; } -static int -pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) -{ - *mode = S_IRUSR | S_IWUSR; - return 0; -} - /* v1 offset per ee */ static int pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) @@ -810,15 +774,15 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. * ppid_to_apid is an in-memory invert of that table. */ - for (apid = pa->last_apid; apid < pa->max_periph; apid++) { - regval = readl_relaxed(pa->cnfg + - SPMI_OWNERSHIP_TABLE_REG(apid)); - pa->apid_data[a
[PATCH V1 02/12] spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other cleanup
This patch cleans up the following. - Rename the "pa" to "pmic_arb". - Rename the spmi_pmic_arb *dev to spmi_pmic_arb *pmic_arb. - Rename the pa_{read,write}_data() functions to pmic_arb_{read,write}_data(). - Rename channel to APID. - Rename the HWIRQ_*() macros to hwirq_to_*(). Signed-off-by: Kiran Gunda --- drivers/spmi/spmi-pmic-arb.c | 418 +-- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 7531519..530fa11 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -39,7 +39,7 @@ #define PMIC_ARB_WDATA10x14 #define PMIC_ARB_RDATA00x18 #define PMIC_ARB_RDATA10x1C -#define PMIC_ARB_REG_CHNL(N) (0x800 + 0x4 * (N)) +#define PMIC_ARB_REG_APID(N) (0x800 + 0x4 * (N)) /* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) @@ -51,7 +51,7 @@ #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ -#define PMIC_ARB_CHAN_VALIDBIT(15) +#define PMIC_ARB_APID_VALIDBIT(15) /* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N))) @@ -97,16 +97,16 @@ enum pmic_arb_cmd_op_code { /* interrupt enable bit */ #define SPMI_PIC_ACC_ENABLE_BITBIT(0) -#define HWIRQ(slave_id, periph_id, irq_id, apid) \ +#define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ slave_id) & 0xF) << 28) | \ (((periph_id) & 0xFF) << 20) | \ (((irq_id)& 0x7) << 16) | \ (((apid) & 0x1FF) << 0)) -#define HWIRQ_SID(hwirq) (((hwirq) >> 28) & 0xF) -#define HWIRQ_PER(hwirq) (((hwirq) >> 20) & 0xFF) -#define HWIRQ_IRQ(hwirq) (((hwirq) >> 16) & 0x7) -#define HWIRQ_APID(hwirq) (((hwirq) >> 0) & 0x1FF) +#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) +#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) +#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) +#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF) struct pmic_arb_ver_ops; @@ -132,7 +132,7 @@ struct apid_data { * @domain:irq domain object for PMIC IRQ domain * @spmic: SPMI controller object * @ver_ops: version dependent operations. - * @ppid_to_apid in-memory copy of PPID -> channel (APID) mapping table. + * @ppid_to_apid in-memory copy of PPID -> APID mapping table. */ struct spmi_pmic_arb { void __iomem*rd_base; @@ -178,10 +178,10 @@ struct spmi_pmic_arb { */ struct pmic_arb_ver_ops { const char *ver_str; - int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, + int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, u16 *apid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, u32 *offset); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); @@ -192,56 +192,57 @@ struct pmic_arb_ver_ops { u32 (*irq_clear)(u16 n); }; -static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa, +static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, u32 offset, u32 val) { - writel_relaxed(val, pa->wr_base + offset); + writel_relaxed(val, pmic_arb->wr_base + offset); } -static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa, +static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb, u32 offset, u32 val) { - writel_relaxed(val, pa->rd_base + offset); + writel_relaxed(val, pmic_arb->rd_base + offset); } /** - * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf + * pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf * @bc:byte count -1. range: 0..3 * @reg: register's address * @buf: output parameter, length must be bc + 1 */ -static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc) +static void +pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc) { - u32 data = __raw_readl(pa->rd_base + reg); + u32 data = __raw_readl(pmic_arb->rd_base + reg); memcpy(buf, &data, (bc & 3) + 1); } /** - * pa_write_data: write 1..4 bytes from buf to pmic-arb's register + * pmic_arb_write_data: write 1..4 bytes from buf to pmic-arb's register *
[PATCH V1 00/12]: spmi: pmic-arb: Support for HW v5 and other fixes
* This patch series add the support for pmic arbiter hardware v5 along with the few bug fixes and code cleanup. * This new series is the combined series of [PATCH V3 0/5]: spmi: pmic-arb: Fixup patches and [PATCH V4 0/4]: spmi: pmic-arb: support for V5 HW and bug fixes, which are being reviewed by Stephen Boyd. * This series depends on the below patch uploaded by Stephen Boyd https://patchwork.kernel.org/patch/9810723/. David Collins (1): spmi: pmic-arb: add support for HW version 5 Fenglin Wu (1): spmi: pmic-arb: Remove checking opc value not less than 0 Kiran Gunda (10): spmi: pmic-arb: remove the read/write access checks spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other cleanup spmi: pmic-arb: clean up pmic_arb_find_apid function spmi: pmic-arb: optimize qpnpint_irq_set_type function spmi: pmic-arb: fix memory allocation for mapping_table spmi: pmic-arb: replace the writel_relaxed with __raw_writel spmi: pmic-arb: return the value instead of passing by pointer spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability spmi: pmic-arb: return __iomem pointer instead of offset spmi: pmic-arb: fix a possible null pointer dereference drivers/spmi/spmi-pmic-arb.c | 825 +-- 1 file changed, 481 insertions(+), 344 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V1 06/12] spmi: pmic-arb: replace the writel_relaxed with __raw_writel
Replace the writel_relaxed with __raw_writel to avoid byte swapping in pmic_arb_write_data() function. That way the code is independent of the CPU endianness. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index b32b5b0..a18ff99 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -230,7 +230,7 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, u32 data = 0; memcpy(&data, buf, (bc & 3) + 1); - pmic_arb_base_write(pmic_arb, reg, data); + __raw_writel(data, pmic_arb->wr_base + reg); } static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 4/4] spmi: pmic-arb: Remove checking opc value not less than 0
From: Fenglin Wu The opc parameter in pmic_arb_write_cmd() function is defined with type u8 and it's always greater than or equal to 0. Checking that it's not less than 0 is redundant and it can cause a forbidden warning during compilation. Remove the check. Signed-off-by: Fenglin Wu Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index d51329e..49abfa7 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017, 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 @@ -419,7 +419,7 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, /* Check the opcode */ if (opc >= 0x40 && opc <= 0x5F) opc = PMIC_ARB_OP_WRITE; - else if (opc >= 0x00 && opc <= 0x0F) + else if (opc <= 0x0F) opc = PMIC_ARB_OP_EXT_WRITE; else if (opc >= 0x30 && opc <= 0x37) opc = PMIC_ARB_OP_EXT_WRITEL; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 2/4] spmi: pmic-arb: fix a possible null pointer dereference
If "core" memory resource is not specified, then the driver could end up dereferencing a null pointer. Fix this issue. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 8982591..156f776 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -956,14 +956,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pmic_arb->spmic = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); - pmic_arb->core_size = resource_size(res); - core = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(core)) { err = PTR_ERR(core); goto err_put_ctrl; } + pmic_arb->core_size = resource_size(res); + pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, sizeof(*pmic_arb->ppid_to_apid), GFP_KERNEL); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V4 1/4] spmi: pmic-arb: return __iomem pointer instead of offset
Modify the pmic_arb version ops to return an __iomem pointer to the address instead of an offset. That way we do not need to care about the base address changes in the new HW version. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 87 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 4824820..8982591 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -167,14 +167,14 @@ struct spmi_pmic_arb { * @offset:on v1 offset of per-ee channel. * on v2 offset of per-ee and per-ppid channel. * @fmt_cmd: formats a GENI/SPMI command. - * @owner_acc_status: on v1 offset of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn - * on v2 offset of SPMI_PIC_OWNERm_ACC_STATUSn. - * @acc_enable:on v1 offset of PMIC_ARB_SPMI_PIC_ACC_ENABLEn - * on v2 offset of SPMI_PIC_ACC_ENABLEn. - * @irq_status:on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_STATUSn - * on v2 offset of SPMI_PIC_IRQ_STATUSn. - * @irq_clear: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_CLEARn - * on v2 offset of SPMI_PIC_IRQ_CLEARn. + * @owner_acc_status: on v1 address of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn + * on v2 address of SPMI_PIC_OWNERm_ACC_STATUSn. + * @acc_enable:on v1 address of PMIC_ARB_SPMI_PIC_ACC_ENABLEn + * on v2 address of SPMI_PIC_ACC_ENABLEn. + * @irq_status:on v1 address of PMIC_ARB_SPMI_PIC_IRQ_STATUSn + * on v2 address of SPMI_PIC_IRQ_STATUSn. + * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn + * on v2 address of SPMI_PIC_IRQ_CLEARn. */ struct pmic_arb_ver_ops { const char *ver_str; @@ -184,10 +184,11 @@ struct pmic_arb_ver_ops { u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ - u32 (*owner_acc_status)(u8 m, u16 n); - u32 (*acc_enable)(u16 n); - u32 (*irq_status)(u16 n); - u32 (*irq_clear)(u16 n); + void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m, + u16 n); + void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); + void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); + void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -476,7 +477,7 @@ static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id) u8 per = ppid & 0xFF; u8 irq_mask = BIT(id); - writel_relaxed(irq_mask, pmic_arb->intr + ver_ops->irq_clear(apid)); + writel_relaxed(irq_mask, ver_ops->irq_clear(pmic_arb, apid)); if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1)) @@ -498,7 +499,7 @@ static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) u32 status; int id; - status = readl_relaxed(pmic_arb->intr + ver_ops->irq_status(apid)); + status = readl_relaxed(ver_ops->irq_status(pmic_arb, apid)); while (status) { id = ffs(status) - 1; status &= ~BIT(id); @@ -517,23 +518,21 @@ static void pmic_arb_chained_irq(struct irq_desc *desc) struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc); const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; struct irq_chip *chip = irq_desc_get_chip(desc); - void __iomem *intr = pmic_arb->intr; int first = pmic_arb->min_apid >> 5; int last = pmic_arb->max_apid >> 5; + u8 ee = pmic_arb->ee; u32 status, enable; int i, id, apid; chained_irq_enter(chip, desc); for (i = first; i <= last; ++i) { - status = readl_relaxed(intr + - ver_ops->owner_acc_status(pmic_arb->ee, i)); + status = readl_relaxed(ver_ops->owner_acc_status(pmic_arb, ee, i)); while (status) { id = ffs(status) - 1; status &= ~BIT(id); apid = id + i * 32; - enable = readl_relaxed(intr + - pmic_arb->ver_ops->acc_enable(apid)); + enable = readl_relaxed(ver_ops->acc_enable(pmic_arb, apid)); if (enable & SPMI_PIC_ACC_ENABLE_BIT) peri
[PATCH V4 3/4] spmi: pmic-arb: add support for HW version 5
From: David Collins Add support for version 5 of the SPMI PMIC arbiter. It utilizes different offsets for registers than those found on version 3. Also, the procedure to determine if writing and IRQ access is allowed for a given PPID changes for version 5. Signed-off-by: David Collins Signed-off-by: Kiran Gunda --- drivers/spmi/spmi-pmic-arb.c | 236 +++ 1 file changed, 214 insertions(+), 22 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 156f776..d51329e 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -29,6 +29,7 @@ #define PMIC_ARB_VERSION 0x #define PMIC_ARB_VERSION_V2_MIN0x2001 #define PMIC_ARB_VERSION_V3_MIN0x3000 +#define PMIC_ARB_VERSION_V5_MIN0x5000 #define PMIC_ARB_INT_EN0x0004 /* PMIC Arbiter channel registers offsets */ @@ -39,7 +40,6 @@ #define PMIC_ARB_WDATA10x14 #define PMIC_ARB_RDATA00x18 #define PMIC_ARB_RDATA10x1C -#define PMIC_ARB_REG_APID(N) (0x800 + 0x4 * (N)) /* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) @@ -52,6 +52,8 @@ #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ #define PMIC_ARB_APID_VALIDBIT(15) +#define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg)((reg) & BIT(24)) +#define INVALID_EE 0xFF /* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N))) @@ -86,6 +88,15 @@ enum pmic_arb_cmd_op_code { PMIC_ARB_OP_ZERO_WRITE = 16, }; +/* + * PMIC arbiter version 5 uses different register offsets for read/write vs + * observer channels. + */ +enum pmic_arb_channel { + PMIC_ARB_CHANNEL_RW, + PMIC_ARB_CHANNEL_OBS, +}; + /* Maximum number of support PMIC peripherals */ #define PMIC_ARB_MAX_PERIPHS 512 #define PMIC_ARB_TIMEOUT_US100 @@ -112,7 +123,8 @@ enum pmic_arb_cmd_op_code { struct apid_data { u16 ppid; - u8 owner; + u8 write_ee; + u8 irq_ee; }; /** @@ -175,12 +187,14 @@ struct spmi_pmic_arb { * on v2 address of SPMI_PIC_IRQ_STATUSn. * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn * on v2 address of SPMI_PIC_IRQ_CLEARn. + * @apid_map_offset: offset of PMIC_ARB_REG_CHNLn */ struct pmic_arb_ver_ops { const char *ver_str; int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr); + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, + enum pmic_arb_channel ch_type); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ @@ -189,6 +203,7 @@ struct pmic_arb_ver_ops { void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); + u32 (*apid_map_offset)(u16 n); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -233,7 +248,8 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, } static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, - void __iomem *base, u8 sid, u16 addr) + void __iomem *base, u8 sid, u16 addr, + enum pmic_arb_channel ch_type) { struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); u32 status = 0; @@ -241,7 +257,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, u32 offset; int rc; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type); if (rc < 0) return rc; @@ -289,7 +305,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW); if (rc < 0) return rc; @@ -298,7 +314,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); - rc = pmic_
[PATCH V4 0/4]: spmi: pmic-arb: support for V5 HW and bug fixes
v4: * spmi: pmic-arb: add support for HW version 5 Clean-up as per Stephen's comments v3: * spmi: pmic-arb: add support for HW version 5 Modified #define INVALID (-1) to #define INVALID_EE0xFF. v2: * spmi: pmic-arb: return __iomem pointer instead of offset Added Stephen's reviewed-by tag. * spmi: pmic-arb: fix a possible null pointer dereference Added Stephen's reviewed-by tag. * spmi: pmic-arb: add support for HW version 5 Modified the pmic_arb_offset_v5 function to return the offset instead of passed by a pointer. * spmi: pmic-arb: Remove checking opc value not less than 0 Added Stephen's reviewed-by tag. Added my sign-off tag. v1: This patch series add the support for pmic arbiter hardware v5 along with the few bug fixes and code cleanup. This patch series is dependent on the below patches and can be merged cleanly only after picking the below patches in to the tree. https://patchwork.kernel.org/patch/9810723/ https://patchwork.kernel.org/patch/9822597/ https://patchwork.kernel.org/patch/9822601/ https://patchwork.kernel.org/patch/9822607/ https://patchwork.kernel.org/patch/9822609/ https://patchwork.kernel.org/patch/9822613/ David Collins (1): spmi: pmic-arb: add support for HW version 5 Fenglin Wu (1): spmi: pmic-arb: Remove checking opc value not less than 0 Kiran Gunda (2): spmi: pmic-arb: return __iomem pointer instead of offset spmi: pmic-arb: fix a possible null pointer dereference drivers/spmi/spmi-pmic-arb.c | 331 ++- 1 file changed, 266 insertions(+), 65 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 3/5] spmi: pmic-arb: replace the writel_relaxed with __raw_writel
Replace the writel_relaxed with __raw_writel to avoid byte swapping in pmic_arb_write_data() function. That way the code is independent of the CPU endianness. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 91b068b..dee562e 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -230,7 +230,7 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, u32 data = 0; memcpy(&data, buf, (bc & 3) + 1); - pmic_arb_base_write(pmic_arb, reg, data); + __raw_writel(data, pmic_arb->wr_base + reg); } static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 0/5]: spmi: pmic-arb: Fixup patches
v3: * spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other code cleanup replaced "i" with "apid" in pmic_arb_find_apid finction. * spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability Added Stephen's reviewed-by tag. v2: * spmi: pmic-arb: remove the read/write access checks Added Stephen's reviewed-by tag. * spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other code cleanup Removed an extra line from the documentation. * spmi: pmic-arb: replace the writel_relaxed with __raw_writel Added Stephen's reviewed-by tag. * spmi: pmic-arb: return the value instead of passing by pointer Added Stephen's reviewed-by tag. Modified the pmic_arb_offset_* function to return the offset instead of passed by a pointer. * spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability Simplified the qpnpint_irq_set_wake function by using the irq_set_irq_wake function instead of using enable_irq_wake/disable_irq_wake. v1: This patch series is to fix-up the comments given by Stephen Boyd on the below 11 pathces. These 11 patches were picked up by GregKH in to his tree and later reviewed by Stephen Boyd. As it is very difficult to revert the changes from his tree, we decided to let these patches go in to Greg's tree and provide the fix-up patches later. Following are the 11 patches picked by Greg: https://patchwork.kernel.org/patch/9754503/ https://patchwork.kernel.org/patch/9754501/ https://patchwork.kernel.org/patch/9754559/ https://patchwork.kernel.org/patch/9754511/ https://patchwork.kernel.org/patch/9754515/ https://patchwork.kernel.org/patch/9754553/ https://patchwork.kernel.org/patch/9754555/ https://patchwork.kernel.org/patch/9754521/ https://patchwork.kernel.org/patch/9754551 https://patchwork.kernel.org/patch/9754525 https://patchwork.kernel.org/patch/9754531/ Also this patch series is dependent on the below patch pushed by Stephen Boyd. Please take this series after taking this patch in to the tree. https://patchwork.kernel.org/patch/9810723/ Kiran Gunda (5): spmi: pmic-arb: remove the read/write access checks spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other code cleanup spmi: pmic-arb: replace the writel_relaxed with __raw_writel spmi: pmic-arb: return the value instead of passing by pointer spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability drivers/spmi/spmi-pmic-arb.c | 563 +++ 1 file changed, 250 insertions(+), 313 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 4/5] spmi: pmic-arb: return the value instead of passing by pointer
Returning the output value from a function, when it is possible, is the better and cleaner way than passing it by the pointer. Hence, modify the ppid_to_apid mapping function to return apid instead of passing it by a pointer. While at it, pass the ppid as function parameter to ppid_to_apid mapping function instead of passing the sid and addr. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 82 +--- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index dee562e..4795092 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -178,11 +178,9 @@ struct spmi_pmic_arb { */ struct pmic_arb_ver_ops { const char *ver_str; - int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, - u16 *apid); + int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, - u32 *offset); + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ @@ -242,10 +240,11 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, u32 offset; int rc; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; offset += PMIC_ARB_STATUS; while (timeout--) { @@ -289,10 +288,11 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); + if (rc < 0) return rc; + offset = rc; cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); raw_spin_lock_irqsave(&pmic_arb->lock, flags); @@ -333,10 +333,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); @@ -383,10 +384,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, int rc; u32 offset; - rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset); - if (rc) + rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); + if (rc < 0) return rc; + offset = rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); @@ -656,8 +658,8 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, unsigned int *out_type) { struct spmi_pmic_arb *pmic_arb = d->host_data; + u16 apid, ppid; int rc; - u16 apid; dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", intspec[0], intspec[1], intspec[2]); @@ -669,14 +671,15 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) return -EINVAL; - rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, intspec[0], - (intspec[1] << 8), &apid); + ppid = intspec[0] << 8 | intspec[1]; + rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid); if (rc < 0) { dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n", intspec[0], intspec[1], intspec[2], rc); return rc; } + apid = rc; /* Keep track of {max,min}_apid for bounding search during interrupt */ if (apid > pmic_arb->max_apid) pmic_arb->max_apid = apid; @@ -705,19 +708,18 @@ static int qpnpint_irq_domain_map(struc
[PATCH V3 1/5] spmi: pmic-arb: remove the read/write access checks
The access mode checks for peripheral ownership for read/write permissions should not be required. Every peripheral enabled for this master is expected to have a read/write permissions. If there is any such invalid access due to wrong configuration in boot loader or device tree files, then it should be fixed in those locations. Hence, remove the access mode checks from the driver. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 75 +++- 1 file changed, 5 insertions(+), 70 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index f4b7a98..7531519 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -128,7 +128,6 @@ struct apid_data { * @ee:the current Execution Environment * @min_apid: minimum APID (used for bounding IRQ search) * @max_apid: maximum APID - * @max_periph:maximum number of PMIC peripherals supported by HW. * @mapping_table: in-memory copy of PPID -> APID mapping table. * @domain:irq domain object for PMIC IRQ domain * @spmic: SPMI controller object @@ -148,7 +147,6 @@ struct spmi_pmic_arb { u8 ee; u16 min_apid; u16 max_apid; - u16 max_periph; u32 *mapping_table; DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS); struct irq_domain *domain; @@ -164,7 +162,6 @@ struct spmi_pmic_arb { * * @ver_str: version string. * @ppid_to_apid: finds the apid for a given ppid. - * @mode: access rights to specified pmic peripheral. * @non_data_cmd: on v1 issues an spmi non-data command. * on v2 no HW support, returns -EOPNOTSUPP. * @offset:on v1 offset of per-ee channel. @@ -183,8 +180,6 @@ struct pmic_arb_ver_ops { const char *ver_str; int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid); - int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, - mode_t *mode); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, u32 *offset); @@ -340,23 +335,11 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u32 cmd; int rc; u32 offset; - mode_t mode; rc = pa->ver_ops->offset(pa, sid, addr, &offset); if (rc) return rc; - rc = pa->ver_ops->mode(pa, sid, addr, &mode); - if (rc) - return rc; - - if (!(mode & S_IRUSR)) { - dev_err(&pa->spmic->dev, - "error: impermissible read from peripheral sid:%d addr:0x%x\n", - sid, addr); - return -EPERM; - } - if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", @@ -402,23 +385,11 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u32 cmd; int rc; u32 offset; - mode_t mode; rc = pa->ver_ops->offset(pa, sid, addr, &offset); if (rc) return rc; - rc = pa->ver_ops->mode(pa, sid, addr, &mode); - if (rc) - return rc; - - if (!(mode & S_IWUSR)) { - dev_err(&pa->spmic->dev, - "error: impermissible write to peripheral sid:%d addr:0x%x\n", - sid, addr); - return -EPERM; - } - if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", @@ -785,13 +756,6 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, return -ENODEV; } -static int -pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) -{ - *mode = S_IRUSR | S_IWUSR; - return 0; -} - /* v1 offset per ee */ static int pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) @@ -810,15 +774,15 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. * ppid_to_apid is an in-memory invert of that table. */ - for (apid = pa->last_apid; apid < pa->max_periph; apid++) { - regval = readl_relaxed(pa->cnfg + - SPMI_OWNERSHIP_TABLE_REG(apid)); - pa->apid_data[a
[PATCH V3 5/5] spmi: pmic-arb: use irq_chip callback to set spmi irq wakeup capability
Currently the driver sets the pmic arbiter core interrupt as wakeup capable irrespective of the child irqs which causes the system to wakeup unnecessarily. To fix this, set the core interrupt as wakeup capable only if any of the child irqs request for it. Do this by marking it as wakeup capable in the irq_set_wake callback. Signed-off-by: Kiran Gunda Reviewed-by: Stephen Boyd --- drivers/spmi/spmi-pmic-arb.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 4795092..4824820 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -623,6 +623,13 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) return 0; } +static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); + + return irq_set_irq_wake(pmic_arb->irq, on); +} + static int qpnpint_get_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool *state) @@ -645,9 +652,9 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, .irq_mask = qpnpint_irq_mask, .irq_unmask = qpnpint_irq_unmask, .irq_set_type = qpnpint_irq_set_type, + .irq_set_wake = qpnpint_irq_set_wake, .irq_get_irqchip_state = qpnpint_get_irqchip_state, - .flags = IRQCHIP_MASK_ON_SUSPEND - | IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, @@ -1069,8 +1076,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq, pmic_arb); - enable_irq_wake(pmic_arb->irq); - err = spmi_controller_add(ctrl); if (err) goto err_domain_remove; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V3 2/5] spmi: pmic-arb: rename pa_xx to pmic_arb_xx and other code cleanup
This patch cleans up the following. - Rename the "pa" to "pmic_arb". - Rename the spmi_pmic_arb *dev to spmi_pmic_arb *pmic_arb. - Rename the pa_{read,write}_data() functions to pmic_arb_{read,write}_data(). - Rename channel to APID. - Rename the HWIRQ_*() macros to hwirq_to_*(). - Clean up qpnpint_irq_set_type() and pmic_arb_find_apid() functions. Signed-off-by: Kiran Gunda --- drivers/spmi/spmi-pmic-arb.c | 453 +-- 1 file changed, 226 insertions(+), 227 deletions(-) diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 7531519..91b068b 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -39,7 +39,7 @@ #define PMIC_ARB_WDATA10x14 #define PMIC_ARB_RDATA00x18 #define PMIC_ARB_RDATA10x1C -#define PMIC_ARB_REG_CHNL(N) (0x800 + 0x4 * (N)) +#define PMIC_ARB_REG_APID(N) (0x800 + 0x4 * (N)) /* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) @@ -51,7 +51,7 @@ #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ -#define PMIC_ARB_CHAN_VALIDBIT(15) +#define PMIC_ARB_APID_VALIDBIT(15) /* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N)(0x0700 + (4 * (N))) @@ -97,16 +97,16 @@ enum pmic_arb_cmd_op_code { /* interrupt enable bit */ #define SPMI_PIC_ACC_ENABLE_BITBIT(0) -#define HWIRQ(slave_id, periph_id, irq_id, apid) \ +#define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ slave_id) & 0xF) << 28) | \ (((periph_id) & 0xFF) << 20) | \ (((irq_id)& 0x7) << 16) | \ (((apid) & 0x1FF) << 0)) -#define HWIRQ_SID(hwirq) (((hwirq) >> 28) & 0xF) -#define HWIRQ_PER(hwirq) (((hwirq) >> 20) & 0xFF) -#define HWIRQ_IRQ(hwirq) (((hwirq) >> 16) & 0x7) -#define HWIRQ_APID(hwirq) (((hwirq) >> 0) & 0x1FF) +#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) +#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) +#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) +#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF) struct pmic_arb_ver_ops; @@ -132,7 +132,7 @@ struct apid_data { * @domain:irq domain object for PMIC IRQ domain * @spmic: SPMI controller object * @ver_ops: version dependent operations. - * @ppid_to_apid in-memory copy of PPID -> channel (APID) mapping table. + * @ppid_to_apid in-memory copy of PPID -> APID mapping table. */ struct spmi_pmic_arb { void __iomem*rd_base; @@ -178,10 +178,10 @@ struct spmi_pmic_arb { */ struct pmic_arb_ver_ops { const char *ver_str; - int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, + int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, u16 *apid); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ - int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, + int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, u32 *offset); u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); @@ -192,56 +192,57 @@ struct pmic_arb_ver_ops { u32 (*irq_clear)(u16 n); }; -static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa, +static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, u32 offset, u32 val) { - writel_relaxed(val, pa->wr_base + offset); + writel_relaxed(val, pmic_arb->wr_base + offset); } -static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa, +static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb, u32 offset, u32 val) { - writel_relaxed(val, pa->rd_base + offset); + writel_relaxed(val, pmic_arb->rd_base + offset); } /** - * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf + * pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf * @bc:byte count -1. range: 0..3 * @reg: register's address * @buf: output parameter, length must be bc + 1 */ -static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc) +static void +pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc) { - u32 data = __raw_readl(pa->rd_base + reg); + u32 data = __raw_readl(pmic_arb->rd_base + reg); memcpy(buf, &data, (bc & 3) + 1); } /** - * pa_write_data: write 1..4 bytes from buf to pmic-arb's register + * pmic_
[PATCH V1] thermal: qcom-spmi-temp-alarm: add support for GEN2 PMIC peripherals
From: David Collins Add support for the TEMP_ALARM GEN2 PMIC peripheral subtype. The GEN2 subtype defines an over temperature state with hysteresis instead of stage in the status register. There are two GEN2 states corresponding to stages 1 and 2. Signed-off-by: David Collins Signed-off-by: Kiran Gunda --- drivers/thermal/qcom-spmi-temp-alarm.c | 92 ++ 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index f502419..a5e17ba 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015, 2017, 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 @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -29,13 +30,17 @@ #define QPNP_TM_REG_ALARM_CTRL 0x46 #define QPNP_TM_TYPE 0x09 -#define QPNP_TM_SUBTYPE0x08 +#define QPNP_TM_SUBTYPE_GEN1 0x08 +#define QPNP_TM_SUBTYPE_GEN2 0x09 -#define STATUS_STAGE_MASK 0x03 +#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0) +#define STATUS_GEN2_STATE_MASK GENMASK(6, 4) +#define STATUS_GEN2_STATE_SHIFT4 -#define SHUTDOWN_CTRL1_THRESHOLD_MASK 0x03 +#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6) +#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0) -#define ALARM_CTRL_FORCE_ENABLE0x80 +#define ALARM_CTRL_FORCE_ENABLEBIT(7) /* * Trip point values based on threshold control @@ -58,6 +63,7 @@ struct qpnp_tm_chip { struct regmap *map; struct thermal_zone_device *tz_dev; + unsigned intsubtype; longtemp; unsigned intthresh; unsigned intstage; @@ -66,6 +72,9 @@ struct qpnp_tm_chip { struct iio_channel *adc; }; +/* This array maps from GEN2 alarm state to GEN1 alarm stage */ +static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3}; + static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data) { unsigned int val; @@ -84,30 +93,59 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data) return regmap_write(chip->map, chip->base + addr, data); } +/** + * qpnp_tm_get_temp_stage() - return over-temperature stage + * @chip: Pointer to the qpnp_tm chip + * + * Return: stage (GEN1) or state (GEN2) on success, or errno on failure. + */ +static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip) +{ + int ret; + u8 reg = 0; + + ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + if (ret < 0) + return ret; + + if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) + ret = reg & STATUS_GEN1_STAGE_MASK; + else + ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT; + + return ret; +} + /* * This function updates the internal temp value based on the * current thermal stage and threshold as well as the previous stage */ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) { - unsigned int stage; + unsigned int stage, stage_new, stage_old; int ret; - u8 reg = 0; - ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) return ret; + stage = ret; - stage = reg & STATUS_STAGE_MASK; + if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) { + stage_new = stage; + stage_old = chip->stage; + } else { + stage_new = alarm_state_map[stage]; + stage_old = alarm_state_map[chip->stage]; + } - if (stage > chip->stage) { + if (stage_new > stage_old) { /* increasing stage, use lower bound */ - chip->temp = (stage - 1) * TEMP_STAGE_STEP + + chip->temp = (stage_new - 1) * TEMP_STAGE_STEP + chip->thresh * TEMP_THRESH_STEP + TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; - } else if (stage < chip->stage) { + } else if (stage_new < stage_old) { /* decreasing stage, use upper bound */ - chip->temp = stage * TEMP_STAGE_STEP + + chip->temp = stage_new * TEMP_STAGE_STEP + chip->thresh * TEMP_THRESH_STEP - TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN