[PATCH V5 1/2] backlight: qcom-wled: Fix FSC update issue for WLED5

2021-03-18 Thread Kiran Gunda
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

2021-03-18 Thread Kiran Gunda
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

2021-03-18 Thread Kiran Gunda
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

2021-03-01 Thread Kiran Gunda
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

2021-03-01 Thread Kiran Gunda
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

2021-03-01 Thread Kiran Gunda
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

2021-03-01 Thread Kiran Gunda
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

2021-03-01 Thread Kiran Gunda
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

2021-03-01 Thread Kiran Gunda
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

2021-02-26 Thread Kiran Gunda
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

2021-02-26 Thread Kiran Gunda
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

2021-02-26 Thread Kiran Gunda
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

2021-02-23 Thread Kiran Gunda
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

2021-02-23 Thread Kiran Gunda
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

2021-02-23 Thread Kiran Gunda
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

2021-02-19 Thread Kiran Gunda
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

2021-02-19 Thread Kiran Gunda
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

2021-02-19 Thread Kiran Gunda
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

2020-12-30 Thread Kiran Gunda
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

2020-12-30 Thread Kiran Gunda
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

2020-12-30 Thread Kiran Gunda
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

2020-12-18 Thread Kiran Gunda
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

2020-12-18 Thread Kiran Gunda
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

2020-12-18 Thread Kiran Gunda
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

2020-12-17 Thread Kiran Gunda
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

2020-12-17 Thread Kiran Gunda
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

2020-12-17 Thread Kiran Gunda
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

2019-10-23 Thread Kiran Gunda
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.

2019-10-16 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2019-10-04 Thread Kiran Gunda
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

2018-08-24 Thread Kiran Gunda
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

2018-08-24 Thread Kiran Gunda
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

2018-08-24 Thread Kiran Gunda
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

2018-05-24 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2018-05-03 Thread Kiran Gunda
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

2017-11-16 Thread Kiran Gunda
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

2017-11-16 Thread Kiran Gunda
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

2017-11-16 Thread Kiran Gunda
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

2017-11-16 Thread Kiran Gunda
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

2017-11-16 Thread Kiran Gunda
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

2017-08-23 Thread Kiran Gunda
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

2017-08-23 Thread Kiran Gunda
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

2017-08-18 Thread Kiran Gunda
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

2017-08-18 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-28 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
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

2017-07-20 Thread Kiran Gunda
* 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

2017-07-20 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-18 Thread Kiran Gunda
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

2017-07-13 Thread Kiran Gunda
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

  1   2   >