Re: [PATCH 03/13] twl4030_charger: correctly handle -EPROBE_DEFER from devm_usb_get_phy_by_node

2015-08-18 Thread NeilBrown
On Tue, 18 Aug 2015 01:07:58 -0700 Tony Lindgren t...@atomide.com
wrote:

 * NeilBrown n...@brown.name [150729 17:29]:
  Now that twl4030_bci_probe can safely return -EPROBE_DEFER,
  do so when devm_usb_get_phy_by_node returns that error.
  
  Signed-off-by: NeilBrown n...@brown.name
  ---
   drivers/power/twl4030_charger.c |6 +-
   1 file changed, 5 insertions(+), 1 deletion(-)
  
  diff --git a/drivers/power/twl4030_charger.c 
  b/drivers/power/twl4030_charger.c
  index 045238370d3f..ffc123fb7158 100644
  --- a/drivers/power/twl4030_charger.c
  +++ b/drivers/power/twl4030_charger.c
  @@ -636,9 +636,13 @@ static int twl4030_bci_probe(struct platform_device 
  *pdev)
   
  phynode = of_find_compatible_node(bci-dev-of_node-parent,
NULL, ti,twl4030-usb);
  -   if (phynode)
  +   if (phynode) {
  bci-transceiver = devm_usb_get_phy_by_node(
  bci-dev, phynode, bci-usb_nb);
  +   if (IS_ERR(bci-transceiver) 
  +   PTR_ERR(bci-transceiver) == -EPROBE_DEFER)
  +   return -EPROBE_DEFER;
  +   }
  }
 
 Neil, the return with -EPROBE_DEFER here causes flakeyness booting
 for me somehow at least on my logicpd-torpedo-37xx-devkit using
 omap2plus_defconfig.
 
 It seems that the twl4030_bci_probe keeps looping or something about
 1/3 of the boots and that probably prevents the other twl modules
 from loading? Reverting this patch alone seems to fix the issue.
 
 I don't think I have a battery wired on this board the USB is wired
 the same way as on beagle-xm. So I'd assume also flakeyness on beagle
 xm with this patch.
 
 Regards,
 
 Tony

What dts file are you using?
I'm guessing that it doesn't have something like:

usb_otg_hs {
interface-type = 0;
usb-phy = usb2_phy;
phys = usb2_phy;
phy-names = usb2-phy;
mode = 3;
power = 50;
};

? i.e. with a usb-phy=usb2_phy ?

What if you add

usb2_phy {
 status = disabled;
}

to your dts file?

Should the 'status' be disabled in twl4030.dtsi, and then marked OK in
any dts that uses it?  I'm not at all clear on how 'status' is meant to
be used.

Thanks,
NeilBrown

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 07/13] twl4030_charger: distinguish between USB current and 'AC' current

2015-08-06 Thread NeilBrown
On Fri, 7 Aug 2015 07:13:09 +0200 Sebastian Reichel s...@kernel.org
wrote:

 Hi,
 
 This actually slipped through my review. IMHO madc should be
 accessed through IIO, as already done for twl4030-madc-battery
 and rx51-battery. That way the custom API can be removed at
 some point.
 
 Anyway, I queued the below patch with Tony's ACK to fix the build
 issue in next.
 

OK, thanks.

I'll try to figure out are more proper approach ... might be a week or
so though.

Thanks,
NeilBrown


pgpEQ176T2qUB.pgp
Description: OpenPGP digital signature


Re: [PATCH 07/13] twl4030_charger: distinguish between USB current and 'AC' current

2015-08-06 Thread NeilBrown
On Thu, 6 Aug 2015 20:11:16 -0700 Tony Lindgren t...@atomide.com
wrote:

 * NeilBrown n...@brown.name [150729 17:28]:
  --- a/drivers/power/twl4030_charger.c
  +++ b/drivers/power/twl4030_charger.c
   static int twl4030_charger_update_current(struct twl4030_bci *bci)
   {
  int status;
  +   int cur;
  unsigned reg, cur_reg;
  u8 bcictl1, oldreg, fullreg;
  bool cgain = false;
  u8 boot_bci;
   
  +   /*
  +* If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
  +* and AC is enabled, set current for 'ac'
  +*/
  +   if (twl4030_get_madc_conversion(11)  4500) {
  +   cur = bci-ac_cur;
  +   bci-ac_is_active = true;
  +   } else {
  +   cur = bci-usb_cur;
  +   bci-ac_is_active = false;
  +   }
  +
  /* First, check thresholds and see if cgain is needed */
  if (bci-ichg_eoc = 20)
  cgain = true;
 
 Neil, you need a stub or something for twl4030_get_madc_conversion
 if madc is not selected. Now at least omap2plus_defconfig and
 ARM allmodconfig fails in Linux next.
 
 Regards,
 
 Tony

Thanks, I did get notified about that by Fengguang's test robot, but
it's still on my list

I guess making CHARGER_TWL4030 auto-select TWL4030_MADC would not be
acceptable?  That would pull in IIO (it didn't use to...).

If this OK?

Thanks,
NeilBrown


From: NeilBrown n...@brown.name
Date: Fri, 7 Aug 2015 13:44:37 +1000
Subject: [PATCH] twl4030_charger: fix compile error when TWL4030_MADC not
 available.

We can only use the madc to check for 'ac' availability
if the madc has been compiled in.
If not: assume always using USB.

Reported-by: Tony Lindgren t...@atomide.com
Signed-off-by: NeilBrown n...@brown.name

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index c7432f532a83..265fd236f4c0 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -91,6 +91,21 @@
 #define TWL4030_MSTATEC_COMPLETE1  0x0b
 #define TWL4030_MSTATEC_COMPLETE4  0x0e
 
+#if IS_ENABLED(CONFIG_TWL4030_MADC)
+/*
+ * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
+ * then AC is available.
+ */
+static inline int ac_available(void)
+{
+   return twl4030_get_madc_conversion(11)  4500;
+}
+#else
+static inline int ac_available(void)
+{
+   return 0;
+}
+#endif
 static bool allow_usb;
 module_param(allow_usb, bool, 0644);
 MODULE_PARM_DESC(allow_usb, Allow USB charge drawing default current);
@@ -263,7 +278,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
 * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
 * and AC is enabled, set current for 'ac'
 */
-   if (twl4030_get_madc_conversion(11)  4500) {
+   if (ac_available()) {
cur = bci-ac_cur;
bci-ac_is_active = true;
} else {
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [Gta04-owner] [PATCH 08/14] twl4030_charger: allow max_current to be managed via sysfs.

2015-07-29 Thread NeilBrown
On Mon, 23 Mar 2015 13:14:50 +0100 jake42
jak...@rommel.stw.uni-erlangen.de wrote:

 Hello Neil,
 
 some suggestions:
 
 On 23.03.2015 00:20, NeilBrown wrote:
  From: NeilBrown ne...@suse.de
  diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030
  b/Documentation/ABI/testing/sysfs-class-power-twl4030
  new file mode 100644
  index ..06092209d851
  --- /dev/null
  +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
  @@ -0,0 +1,15 @@
  +What: /sys/class/power_supply/twl4030_ac/max_current
  +  /sys/class/power_supply/twl4030_usb/max_current
  +Description:
  +   Read/Write limit on current which which may
 one less which^^
  +   be drawn from the ac (Accessory Charger) or
  +   USB port.
  +
  +   Value is in micro-Amps.
  +
  +   Value is set automatically to an appropriate
  +   value when a cable is plugged on unplugged.
 s/on/or   ^^
  +
  +   Value can the set by writing to the attribute.
^^ be set?
  +   The change will only persist until the next
  +   plug event.  These event are reported via udev.
 
 Regards
 Jake
 

Thanks.
I've made those two changes.

NeilBrown
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 03/13] twl4030_charger: correctly handle -EPROBE_DEFER from devm_usb_get_phy_by_node

2015-07-29 Thread NeilBrown
Now that twl4030_bci_probe can safely return -EPROBE_DEFER,
do so when devm_usb_get_phy_by_node returns that error.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 045238370d3f..ffc123fb7158 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -636,9 +636,13 @@ static int twl4030_bci_probe(struct platform_device *pdev)
 
phynode = of_find_compatible_node(bci-dev-of_node-parent,
  NULL, ti,twl4030-usb);
-   if (phynode)
+   if (phynode) {
bci-transceiver = devm_usb_get_phy_by_node(
bci-dev, phynode, bci-usb_nb);
+   if (IS_ERR(bci-transceiver) 
+   PTR_ERR(bci-transceiver) == -EPROBE_DEFER)
+   return -EPROBE_DEFER;
+   }
}
 
/* Enable interrupts now. */


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 02/13] twl4030_charger: convert to module_platform_driver instead of ..._probe.

2015-07-29 Thread NeilBrown
From: Pavel Machek pa...@ucw.cz

Drivers using module_platform_driver_probe cannot return
EPROBE_DEFER from the probe function, which makes them rather useless
these days...

Convert to module_platform_driver() so EPROBE_DEFER can be used.

Signed-off-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index fe71c61109f5..045238370d3f 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -568,7 +568,7 @@ static const struct power_supply_desc twl4030_bci_usb_desc 
= {
.get_property   = twl4030_bci_get_property,
 };
 
-static int __init twl4030_bci_probe(struct platform_device *pdev)
+static int twl4030_bci_probe(struct platform_device *pdev)
 {
struct twl4030_bci *bci;
const struct twl4030_bci_platform_data *pdata = pdev-dev.platform_data;
@@ -692,14 +692,14 @@ static const struct of_device_id twl_bci_of_match[] = {
 MODULE_DEVICE_TABLE(of, twl_bci_of_match);
 
 static struct platform_driver twl4030_bci_driver = {
+   .probe = twl4030_bci_probe,
.driver = {
.name   = twl4030_bci,
.of_match_table = of_match_ptr(twl_bci_of_match),
},
.remove = __exit_p(twl4030_bci_remove),
 };
-
-module_platform_driver_probe(twl4030_bci_driver, twl4030_bci_probe);
+module_platform_driver(twl4030_bci_driver);
 
 MODULE_AUTHOR(GraÅžvydas Ignotas);
 MODULE_DESCRIPTION(TWL4030 Battery Charger Interface driver);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 06/13] twl4030_charger: allow fine control of charger current.

2015-07-29 Thread NeilBrown
The twl4030 allows control of the incoming current.
Part of this control is a 'CGAIN' setting which doubles
the range for half the precision.  This control affects
several different current setting, so all need to be updated
at once when CGAIN is changed.

With this patch, all of these current setting are managed
by the driver, but most are left at their default settings.

The current drawn is set to 500mA if the allow_usb module parameter is
set, and to 100mA otherwise.
More fine control will appear in later patches.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |  168 +--
 1 file changed, 160 insertions(+), 8 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 29984b263a35..3b7cc631bb8a 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -31,6 +31,11 @@
 #define TWL4030_BCIMFSTS4  0x10
 #define TWL4030_BCICTL10x23
 #define TWL4030_BB_CFG 0x12
+#define TWL4030_BCIIREF1   0x27
+#define TWL4030_BCIIREF2   0x28
+#define TWL4030_BCIMFKEY   0x11
+#define TWL4030_BCIMFTH8   0x1d
+#define TWL4030_BCIMFTH9   0x1e
 
 #define TWL4030_BCIMFSTS1  0x01
 
@@ -95,6 +100,12 @@ struct twl4030_bci {
int irq_bci;
int usb_enabled;
 
+   /*
+* ichg values in uA. If any are 'large', we set CGAIN to
+* '1' which doubles the range for half the precision.
+*/
+   unsigned intichg_eoc, ichg_lo, ichg_hi, cur;
+
unsigned long   event;
 };
 
@@ -211,6 +222,146 @@ static int ua2regval(int ua, bool cgain)
return ret;
 }
 
+static int twl4030_charger_update_current(struct twl4030_bci *bci)
+{
+   int status;
+   unsigned reg, cur_reg;
+   u8 bcictl1, oldreg, fullreg;
+   bool cgain = false;
+   u8 boot_bci;
+
+   /* First, check thresholds and see if cgain is needed */
+   if (bci-ichg_eoc = 20)
+   cgain = true;
+   if (bci-ichg_lo = 40)
+   cgain = true;
+   if (bci-ichg_hi = 82)
+   cgain = true;
+   if (bci-cur  852000)
+   cgain = true;
+
+   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
+   if (status  0)
+   return status;
+   if (twl_i2c_read_u8(TWL_MODULE_PM_MASTER, boot_bci,
+   TWL4030_PM_MASTER_BOOT_BCI)  0)
+   boot_bci = 0;
+   boot_bci = 7;
+
+   if ((!!cgain) != !!(bcictl1  TWL4030_CGAIN))
+   /* Need to turn for charging while we change the
+* CGAIN bit.  Leave it off while everything is
+* updated.
+*/
+   twl4030_clear_set_boot_bci(boot_bci, 0);
+
+   /*
+* For ichg_eoc, the hardware only supports reg values matching
+* 100000, and requires the  be stored in the high nibble
+* of TWL4030_BCIMFTH8.
+*/
+   reg = ua2regval(bci-ichg_eoc, cgain);
+   if (reg  0x278)
+   reg = 0x278;
+   if (reg  0x200)
+   reg = 0x200;
+   reg = (reg  3)  0xf;
+   fullreg = reg  4;
+
+   /*
+* For ichg_lo, reg value must match 10.
+*  is stored in low nibble of TWL4030_BCIMFTH8.
+*/
+   reg = ua2regval(bci-ichg_lo, cgain);
+   if (reg  0x2F0)
+   reg = 0x2F0;
+   if (reg  0x200)
+   reg = 0x200;
+   reg = (reg  4)  0xf;
+   fullreg |= reg;
+
+   /* ichg_eoc and ichg_lo live in same register */
+   status = twl4030_bci_read(TWL4030_BCIMFTH8, oldreg);
+   if (status  0)
+   return status;
+   if (oldreg != fullreg) {
+   status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xF4,
+ TWL4030_BCIMFKEY);
+   if (status  0)
+   return status;
+   twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+fullreg, TWL4030_BCIMFTH8);
+   }
+
+   /* ichg_hi threshold must be 101100 (I think) */
+   reg = ua2regval(bci-ichg_hi, cgain);
+   if (reg  0x3E0)
+   reg = 0x3E0;
+   if (reg  0x200)
+   reg = 0x200;
+   fullreg = (reg  5)  0xF;
+   fullreg = 4;
+   status = twl4030_bci_read(TWL4030_BCIMFTH9, oldreg);
+   if (status  0)
+   return status;
+   if ((oldreg  0xF0) != fullreg) {
+   fullreg |= (oldreg  0x0F);
+   status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7,
+ TWL4030_BCIMFKEY);
+   if (status  0)
+   return status;
+   twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+fullreg, TWL4030_BCIMFTH9

[PATCH 00/13] Enhance twl4030_charger functionality. - V3

2015-07-29 Thread NeilBrown

Following is most of my twl4030_charger patches, rebased against
 git://git.infradead.org/battery-2.6

Since the previous set I have added the conversion to
module_platform_driver so EPROBE_DEFER can be used, and fixed
a few minor typos.

This does not include the changes to add extcon support, in part
because extcon has seen some changes lately which leave me even more
confused about how best to use it than before.
I need to sort that out before I can resolve the rest of my usb phy
patches and then add a few more charger patches.

Thanks,
NeilBrown


---

NeilBrown (12):
  twl4030_charger: use runtime_pm to keep usb phy active while charging.
  twl4030_charger: correctly handle -EPROBE_DEFER from 
devm_usb_get_phy_by_node
  twl4030_charger: trust phy to determine when USB power is available.
  twl4030_charger: split uA calculation into a function.
  twl4030_charger: allow fine control of charger current.
  twl4030_charger: distinguish between USB current and 'AC' current
  twl4030_charger: allow max_current to be managed via sysfs.
  twl4030_charger: enable manual enable/disable of usb charging.
  twl4030_charger: add software controlled linear charging mode.
  twl4030_charger: add ac/mode to match usb/mode
  twl4030_charger: Increase current carefully while watching voltage.
  twl4030_charger: assume a 'charger' can supply maximum current.

Pavel Machek (1):
  twl4030_charger: convert to module_platform_driver instead of ..._probe.


 .../ABI/testing/sysfs-class-power-twl4030  |   45 ++
 drivers/mfd/twl-core.c |9 
 drivers/power/twl4030_charger.c|  541 ++--
 3 files changed, 531 insertions(+), 64 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-power-twl4030

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 08/13] twl4030_charger: allow max_current to be managed via sysfs.

2015-07-29 Thread NeilBrown
'max_current' sysfs attributes are created which allow the
max to be set.
Whenever a current source changes, the default is restored.
This will be followed by a uevent, so user-space can decide to
update again.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 .../ABI/testing/sysfs-class-power-twl4030  |   15 
 drivers/power/twl4030_charger.c|   72 
 2 files changed, 87 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-power-twl4030

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
new file mode 100644
index ..0331bba4605d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -0,0 +1,15 @@
+What: /sys/class/power_supply/twl4030_ac/max_current
+  /sys/class/power_supply/twl4030_usb/max_current
+Description:
+   Read/Write limit on current which may
+   be drawn from the ac (Accessory Charger) or
+   USB port.
+
+   Value is in micro-Amps.
+
+   Value is set automatically to an appropriate
+   value when a cable is plugged or unplugged.
+
+   Value can the set by writing to the attribute.
+   The change will only persist until the next
+   plug event.  These event are reported via udev.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 982675df21b7..b0a50adebfda 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -482,6 +482,8 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void 
*arg)
struct twl4030_bci *bci = arg;
 
dev_dbg(bci-dev, CHG_PRES irq\n);
+   /* reset current on each 'plug' event */
+   bci-ac_cur = 50;
twl4030_charger_update_current(bci);
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
@@ -536,6 +538,63 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void 
*arg)
return IRQ_HANDLED;
 }
 
+/*
+ * Provide max_current attribute in sysfs.
+ */
+static ssize_t
+twl4030_bci_max_current_store(struct device *dev, struct device_attribute 
*attr,
+   const char *buf, size_t n)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int cur = 0;
+   int status = 0;
+   status = kstrtoint(buf, 10, cur);
+   if (status)
+   return status;
+   if (cur  0)
+   return -EINVAL;
+   if (dev == bci-ac-dev)
+   bci-ac_cur = cur;
+   else
+   bci-usb_cur = cur;
+
+   twl4030_charger_update_current(bci);
+   return n;
+}
+
+/*
+ * sysfs max_current show
+ */
+static ssize_t twl4030_bci_max_current_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   int status = 0;
+   int cur = -1;
+   u8 bcictl1;
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+
+   if (dev == bci-ac-dev) {
+   if (!bci-ac_is_active)
+   cur = bci-ac_cur;
+   } else {
+   if (bci-ac_is_active)
+   cur = bci-usb_cur;
+   }
+   if (cur  0) {
+   cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
+   if (cur  0)
+   return cur;
+   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
+   if (status  0)
+   return status;
+   cur = regval2ua(cur, bcictl1  TWL4030_CGAIN);
+   }
+   return scnprintf(buf, PAGE_SIZE, %u\n, cur);
+}
+
+static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show,
+   twl4030_bci_max_current_store);
+
 static void twl4030_bci_usb_work(struct work_struct *data)
 {
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
@@ -558,6 +617,12 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
 
dev_dbg(bci-dev, OTG notify %lu\n, val);
 
+   /* reset current on each 'plug' event */
+   if (allow_usb)
+   bci-usb_cur = 50;
+   else
+   bci-usb_cur = 10;
+
bci-event = val;
schedule_work(bci-work);
 
@@ -831,6 +896,11 @@ static int twl4030_bci_probe(struct platform_device *pdev)
dev_warn(pdev-dev, failed to unmask interrupts: %d\n, ret);
 
twl4030_charger_update_current(bci);
+   if (device_create_file(bci-usb-dev, dev_attr_max_current))
+   dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-ac-dev, dev_attr_max_current))
+   dev_warn(pdev-dev, could not create sysfs file\n);
+
twl4030_charger_enable_ac(true);
if (!IS_ERR_OR_NULL(bci-transceiver))
twl4030_bci_usb_ncb(bci-usb_nb,
@@ -855,6 +925,8 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
twl4030_charger_enable_usb(bci, false

[PATCH 04/13] twl4030_charger: trust phy to determine when USB power is available.

2015-07-29 Thread NeilBrown
The usb phy driver already determines when VBUS is available,
so repeating the test in the charger driver is pointless duplication.

On probe, process the last event from the phy, and from then on,
do whatever the phy tells us without double-checking.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |   33 ++---
 1 file changed, 6 insertions(+), 27 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index ffc123fb7158..a075216d65ed 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -178,28 +178,6 @@ static int twl4030_is_battery_present(struct twl4030_bci 
*bci)
 }
 
 /*
- * Check if VBUS power is present
- */
-static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
-{
-   int ret;
-   u8 hwsts;
-
-   ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, hwsts,
- TWL4030_PM_MASTER_STS_HW_CONDITIONS);
-   if (ret  0)
-   return 0;
-
-   dev_dbg(bci-dev, check_vbus: HW_CONDITIONS %02x\n, hwsts);
-
-   /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */
-   if ((hwsts  TWL4030_STS_VBUS)  !(hwsts  TWL4030_STS_USB_ID))
-   return 1;
-
-   return 0;
-}
-
-/*
  * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
@@ -207,10 +185,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
int ret;
 
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
-   /* Check for USB charger connected */
-   if (!twl4030_bci_have_vbus(bci))
-   return -ENODEV;
-
/*
 * Until we can find out what current the device can provide,
 * require a module param to enable USB charging.
@@ -662,7 +636,12 @@ static int twl4030_bci_probe(struct platform_device *pdev)
dev_warn(pdev-dev, failed to unmask interrupts: %d\n, ret);
 
twl4030_charger_enable_ac(true);
-   twl4030_charger_enable_usb(bci, true);
+   if (!IS_ERR_OR_NULL(bci-transceiver))
+   twl4030_bci_usb_ncb(bci-usb_nb,
+   bci-transceiver-last_event,
+   NULL);
+   else
+   twl4030_charger_enable_usb(bci, false);
if (pdata)
twl4030_charger_enable_backup(pdata-bb_uvolt,
  pdata-bb_uamp);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 09/13] twl4030_charger: enable manual enable/disable of usb charging.

2015-07-29 Thread NeilBrown
'off' or 'auto' to

 /sys/class/power/twl4030_usb/mode

will now enable or disable charging from USB port.  Normally this is
enabled on 'plug' and disabled on 'unplug'.
Unplug will still disable charging.  'plug' will only enable it if
'auto' if selected.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 .../ABI/testing/sysfs-class-power-twl4030  |   11 
 drivers/power/twl4030_charger.c|   59 
 2 files changed, 70 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
index 0331bba4605d..40e0f919cbde 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -13,3 +13,14 @@ Description:
Value can the set by writing to the attribute.
The change will only persist until the next
plug event.  These event are reported via udev.
+
+
+What: /sys/class/power_supply/twl4030_usb/mode
+Description:
+   Changing mode for USB port.
+   Writing to this can disable charging.
+
+   Possible values are:
+   auto - draw power as appropriate for detected
+power source and battery status.
+   off  - do not draw any power.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index b0a50adebfda..6fa928ed3128 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -109,10 +109,16 @@ struct twl4030_bci {
unsigned intichg_eoc, ichg_lo, ichg_hi;
unsigned intusb_cur, ac_cur;
boolac_is_active;
+   int usb_mode; /* charging mode requested */
+#defineCHARGE_OFF  0
+#defineCHARGE_AUTO 1
 
unsigned long   event;
 };
 
+/* strings for 'usb_mode' values */
+static char *modes[] = { off, auto };
+
 /*
  * clear and set bits on an given register on a given module
  */
@@ -386,6 +392,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 {
int ret;
 
+   if (bci-usb_mode == CHARGE_OFF)
+   enable = false;
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
 
twl4030_charger_update_current(bci);
@@ -629,6 +637,53 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
return NOTIFY_OK;
 }
 
+/*
+ * sysfs charger enabled store
+ */
+static ssize_t
+twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int mode;
+   int status;
+
+   if (sysfs_streq(buf, modes[0]))
+   mode = 0;
+   else if (sysfs_streq(buf, modes[1]))
+   mode = 1;
+   else
+   return -EINVAL;
+   twl4030_charger_enable_usb(bci, false);
+   bci-usb_mode = mode;
+   status = twl4030_charger_enable_usb(bci, true);
+   return (status == 0) ? n : status;
+}
+
+/*
+ * sysfs charger enabled show
+ */
+static ssize_t
+twl4030_bci_mode_show(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int len = 0;
+   int i;
+
+   for (i = 0; i  ARRAY_SIZE(modes); i++)
+   if (bci-usb_mode == i)
+   len += snprintf(buf+len, PAGE_SIZE-len,
+   [%s] , modes[i]);
+   else
+   len += snprintf(buf+len, PAGE_SIZE-len,
+   %s , modes[i]);
+   buf[len-1] = '\n';
+   return len;
+}
+static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show,
+  twl4030_bci_mode_store);
+
 static int twl4030_charger_get_current(void)
 {
int curr;
@@ -815,6 +870,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
bci-usb_cur = 50;  /* 500mA */
else
bci-usb_cur = 10;  /* 100mA */
+   bci-usb_mode = CHARGE_AUTO;
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);
@@ -898,6 +954,8 @@ static int twl4030_bci_probe(struct platform_device *pdev)
twl4030_charger_update_current(bci);
if (device_create_file(bci-usb-dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-usb-dev, dev_attr_mode))
+   dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-ac-dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
 
@@ -926,6 +984,7 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
twl4030_charger_enable_backup(0, 0);
 
device_remove_file(bci-usb-dev

[PATCH 07/13] twl4030_charger: distinguish between USB current and 'AC' current

2015-07-29 Thread NeilBrown

The twl4030 charger has two current sources, 'USB' and 'AC'
(presumably Accessory Charger because it isn't Alternating Current).

If 'AC' is providing current, we should set the current limit
differently to when it isn't (and so USB is used).
So split 'cur' into 'usb_cur' and 'ac_cur' and use accordingly.

Now we must review the current setting on any interrupt or USB
event which might indicate that the charger-source has changed.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |   36 +---
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 3b7cc631bb8a..982675df21b7 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,6 +22,7 @@
 #include linux/power_supply.h
 #include linux/notifier.h
 #include linux/usb/otg.h
+#include linux/i2c/twl4030-madc.h
 
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
@@ -101,10 +102,13 @@ struct twl4030_bci {
int usb_enabled;
 
/*
-* ichg values in uA. If any are 'large', we set CGAIN to
-* '1' which doubles the range for half the precision.
+* ichg_* and *_cur values in uA. If any are 'large', we set
+* CGAIN to '1' which doubles the range for half the
+* precision.
 */
-   unsigned intichg_eoc, ichg_lo, ichg_hi, cur;
+   unsigned intichg_eoc, ichg_lo, ichg_hi;
+   unsigned intusb_cur, ac_cur;
+   boolac_is_active;
 
unsigned long   event;
 };
@@ -225,11 +229,24 @@ static int ua2regval(int ua, bool cgain)
 static int twl4030_charger_update_current(struct twl4030_bci *bci)
 {
int status;
+   int cur;
unsigned reg, cur_reg;
u8 bcictl1, oldreg, fullreg;
bool cgain = false;
u8 boot_bci;
 
+   /*
+* If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
+* and AC is enabled, set current for 'ac'
+*/
+   if (twl4030_get_madc_conversion(11)  4500) {
+   cur = bci-ac_cur;
+   bci-ac_is_active = true;
+   } else {
+   cur = bci-usb_cur;
+   bci-ac_is_active = false;
+   }
+
/* First, check thresholds and see if cgain is needed */
if (bci-ichg_eoc = 20)
cgain = true;
@@ -237,7 +254,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
cgain = true;
if (bci-ichg_hi = 82)
cgain = true;
-   if (bci-cur  852000)
+   if (cur  852000)
cgain = true;
 
status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
@@ -318,7 +335,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
 * And finally, set the current.  This is stored in
 * two registers.
 */
-   reg = ua2regval(bci-cur, cgain);
+   reg = ua2regval(cur, cgain);
/* we have only 10 bits */
if (reg  0x3ff)
reg = 0x3ff;
@@ -371,6 +388,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
 
+   twl4030_charger_update_current(bci);
+
/* Need to keep phy powered */
if (!bci-usb_enabled) {
pm_runtime_get_sync(bci-transceiver-dev);
@@ -463,6 +482,7 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void 
*arg)
struct twl4030_bci *bci = arg;
 
dev_dbg(bci-dev, CHG_PRES irq\n);
+   twl4030_charger_update_current(bci);
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
 
@@ -495,6 +515,7 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
}
+   twl4030_charger_update_current(bci);
 
/* various monitoring events, for now we just log them here */
if (irqs1  (TWL4030_TBATOR2 | TWL4030_TBATOR1))
@@ -724,10 +745,11 @@ static int twl4030_bci_probe(struct platform_device *pdev)
bci-ichg_eoc = 80100; /* Stop charging when current drops to here */
bci-ichg_lo = 241000; /* Low threshold */
bci-ichg_hi = 50; /* High threshold */
+   bci-ac_cur = 50; /* 500mA */
if (allow_usb)
-   bci-cur = 50;  /* 500mA */
+   bci-usb_cur = 50;  /* 500mA */
else
-   bci-cur = 10;  /* 100mA */
+   bci-usb_cur = 10;  /* 100mA */
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org

[PATCH 05/13] twl4030_charger: split uA calculation into a function.

2015-07-29 Thread NeilBrown
We will need this calculation in other places, so
create functions to map between register value and uA value.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |   48 ---
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index a075216d65ed..29984b263a35 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -178,6 +178,40 @@ static int twl4030_is_battery_present(struct twl4030_bci 
*bci)
 }
 
 /*
+ * TI provided formulas:
+ * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
+ * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
+ * Here we use integer approximation of:
+ * CGAIN == 0: val * 1.6618 - 0.85 * 1000
+ * CGAIN == 1: (val * 1.6618 - 0.85 * 1000) * 2
+ */
+/*
+ * convert twl register value for currents into uA
+ */
+static int regval2ua(int regval, bool cgain)
+{
+   if (cgain)
+   return (regval * 16618 - 8500 * 1000) / 5;
+   else
+   return (regval * 16618 - 8500 * 1000) / 10;
+}
+
+/*
+ * convert uA currents into twl register value
+ */
+static int ua2regval(int ua, bool cgain)
+{
+   int ret;
+   if (cgain)
+   ua /= 2;
+   ret = (ua * 10 + 8500 * 1000) / 16618;
+   /* rounding problems */
+   if (ret  512)
+   ret = 512;
+   return ret;
+}
+
+/*
  * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
@@ -366,14 +400,6 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
return NOTIFY_OK;
 }
 
-/*
- * TI provided formulas:
- * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
- * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
- * Here we use integer approximation of:
- * CGAIN == 0: val * 1.6618 - 0.85
- * CGAIN == 1: (val * 1.6618 - 0.85) * 2
- */
 static int twl4030_charger_get_current(void)
 {
int curr;
@@ -388,11 +414,7 @@ static int twl4030_charger_get_current(void)
if (ret)
return ret;
 
-   ret = (curr * 16618 - 850 * 1) / 10;
-   if (bcictl1  TWL4030_CGAIN)
-   ret *= 2;
-
-   return ret;
+   return regval2ua(curr, bcictl1  TWL4030_CGAIN);
 }
 
 /*


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/13] twl4030_charger: use runtime_pm to keep usb phy active while charging.

2015-07-29 Thread NeilBrown
The twl4030 usb phy needs to be active while we are using
the USB VBUS as a current source for charging.
In particular, the usb3v1 regulator must be enabled and the
PHY_PWR_PHYPWD bit must be set to keep the phy powered.

commit ab37813f4093a5f59cb8e083cde277289dc72ed3
twl4030_charger: Allow charger to control the regulator that feeds it

gave the charger control over the regulator, but didn't resolve
the PHY_PWR_PHYPWD issue.

Now that both of these are controlled by runtime_pm in
phy-twl4030-usb, we can simply take a runtime_pm reference to the USB
phy whenever the charger wants to use it as a current source.

So this patch reverts the above commit, and adds the necessary
runtime_pm calls.

Acked-by: Lee Jones lee.jo...@linaro.org
Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mfd/twl-core.c  |9 -
 drivers/power/twl4030_charger.c |   18 +-
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 489674a2497e..831696ee2472 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -788,9 +788,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
static struct regulator_consumer_supply usb1v8 = {
.supply =   usb1v8,
};
-   static struct regulator_consumer_supply usb3v1[] = {
-   { .supply = usb3v1 },
-   { .supply = bci3v1 },
+   static struct regulator_consumer_supply usb3v1 = {
+   .supply =   usb3v1,
};
 
/* First add the regulators so that they can be used by transceiver */
@@ -818,7 +817,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
return PTR_ERR(child);
 
child = add_regulator_linked(TWL4030_REG_VUSB3V1,
- usb_fixed, usb3v1, 2,
+ usb_fixed, usb3v1, 1,
  features);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -838,7 +837,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)  child) {
usb1v5.dev_name = dev_name(child);
usb1v8.dev_name = dev_name(child);
-   usb3v1[0].dev_name = dev_name(child);
+   usb3v1.dev_name = dev_name(child);
}
}
 
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 709d90dc75f1..fe71c61109f5 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,7 +22,6 @@
 #include linux/power_supply.h
 #include linux/notifier.h
 #include linux/usb/otg.h
-#include linux/regulator/machine.h
 
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
@@ -94,7 +93,6 @@ struct twl4030_bci {
struct work_struct  work;
int irq_chg;
int irq_bci;
-   struct regulator*usb_reg;
int usb_enabled;
 
unsigned long   event;
@@ -208,7 +206,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 {
int ret;
 
-   if (enable) {
+   if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
/* Check for USB charger connected */
if (!twl4030_bci_have_vbus(bci))
return -ENODEV;
@@ -222,14 +220,9 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
return -EACCES;
}
 
-   /* Need to keep regulator on */
+   /* Need to keep phy powered */
if (!bci-usb_enabled) {
-   ret = regulator_enable(bci-usb_reg);
-   if (ret) {
-   dev_err(bci-dev,
-   Failed to enable regulator\n);
-   return ret;
-   }
+   pm_runtime_get_sync(bci-transceiver-dev);
bci-usb_enabled = 1;
}
 
@@ -244,7 +237,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
} else {
ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
if (bci-usb_enabled) {
-   regulator_disable(bci-usb_reg);
+   pm_runtime_mark_last_busy(bci-transceiver-dev);
+   pm_runtime_put_autosuspend(bci-transceiver-dev);
bci-usb_enabled = 0;
}
}
@@ -609,8 +603,6 @@ static int __init twl4030_bci_probe(struct

[PATCH 11/13] twl4030_charger: add ac/mode to match usb/mode

2015-07-29 Thread NeilBrown

This allows AC charging to be turned off, much like usb charging.
continuous mode is not available though.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown n...@brown.name
---
 .../ABI/testing/sysfs-class-power-twl4030  |   10 ++
 drivers/power/twl4030_charger.c|   35 +++-
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
index e8baa36aaa2b..be26af0f1895 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -33,3 +33,13 @@ Description:
 This is useful for unstable power sources
 such as bicycle dynamo, but care should
 be taken that battery is not over-charged.
+
+What: /sys/class/power_supply/twl4030_ac/mode
+Description:
+   Changing mode for 'ac' port.
+   Writing to this can disable charging.
+
+   Possible values are:
+   auto - draw power as appropriate for detected
+power source and battery status.
+   off  - do not draw any power.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index de5430deaf23..68117ad23564 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -114,7 +114,7 @@ struct twl4030_bci {
unsigned intichg_eoc, ichg_lo, ichg_hi;
unsigned intusb_cur, ac_cur;
boolac_is_active;
-   int usb_mode; /* charging mode requested */
+   int usb_mode, ac_mode; /* charging mode requested */
 #defineCHARGE_OFF  0
 #defineCHARGE_AUTO 1
 #defineCHARGE_LINEAR   2
@@ -459,10 +459,13 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 /*
  * Enable/Disable AC Charge funtionality.
  */
-static int twl4030_charger_enable_ac(bool enable)
+static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable)
 {
int ret;
 
+   if (bci-ac_mode == CHARGE_OFF)
+   enable = false;
+
if (enable)
ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
else
@@ -688,9 +691,17 @@ twl4030_bci_mode_store(struct device *dev, struct 
device_attribute *attr,
mode = 2;
else
return -EINVAL;
-   twl4030_charger_enable_usb(bci, false);
-   bci-usb_mode = mode;
-   status = twl4030_charger_enable_usb(bci, true);
+   if (dev == bci-ac-dev) {
+   if (mode == 2)
+   return -EINVAL;
+   twl4030_charger_enable_ac(bci, false);
+   bci-ac_mode = mode;
+   status = twl4030_charger_enable_ac(bci, true);
+   } else {
+   twl4030_charger_enable_usb(bci, false);
+   bci-usb_mode = mode;
+   status = twl4030_charger_enable_usb(bci, true);
+   }
return (status == 0) ? n : status;
 }
 
@@ -704,9 +715,13 @@ twl4030_bci_mode_show(struct device *dev,
struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
int len = 0;
int i;
+   int mode = bci-usb_mode;
+
+   if (dev == bci-ac-dev)
+   mode = bci-ac_mode;
 
for (i = 0; i  ARRAY_SIZE(modes); i++)
-   if (bci-usb_mode == i)
+   if (mode == i)
len += snprintf(buf+len, PAGE_SIZE-len,
[%s] , modes[i]);
else
@@ -916,6 +931,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
else
bci-usb_cur = 10;  /* 100mA */
bci-usb_mode = CHARGE_AUTO;
+   bci-ac_mode = CHARGE_AUTO;
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);
@@ -1001,10 +1017,12 @@ static int twl4030_bci_probe(struct platform_device 
*pdev)
dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-usb-dev, dev_attr_mode))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-ac-dev, dev_attr_mode))
+   dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-ac-dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
 
-   twl4030_charger_enable_ac(true);
+   twl4030_charger_enable_ac(bci, true);
if (!IS_ERR_OR_NULL(bci-transceiver))
twl4030_bci_usb_ncb(bci-usb_nb,
bci-transceiver-last_event,
@@ -1024,13 +1042,14 @@ static int __exit twl4030_bci_remove(struct 
platform_device *pdev)
 {
struct twl4030_bci *bci = platform_get_drvdata(pdev);
 
-   twl4030_charger_enable_ac(false);
+   twl4030_charger_enable_ac(bci

[PATCH 13/13] twl4030_charger: assume a 'charger' can supply maximum current.

2015-07-29 Thread NeilBrown
If it cannot, we will stop pulling more current when voltage drops.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 2c537ee11bbe..c7432f532a83 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -697,8 +697,10 @@ static void twl4030_bci_usb_work(struct work_struct *data)
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
 
switch (bci-event) {
-   case USB_EVENT_VBUS:
case USB_EVENT_CHARGER:
+   bci-usb_cur = USB_MAX_CURRENT;
+   /* FALL THROUGH */
+   case USB_EVENT_VBUS:
twl4030_charger_enable_usb(bci, true);
break;
case USB_EVENT_NONE:


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 12/13] twl4030_charger: Increase current carefully while watching voltage.

2015-07-29 Thread NeilBrown

The USB Battery Charging spec (BC1.2) suggests a dedicated
charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25
volts.

To choose the correct current voltage setting requires a trial
and error approach: try to draw current and see if the voltage drops
too low.

Even with a configured Standard Downstream Port, it may not be possible
to reliably pull 500mA - depending on cable quality and source
quality I have reports of charging failure due to the voltage dropping
too low.

To address both these concerns, this patch introduce incremental
current setting.
The current pull from VBUS is increased in steps of 20mA every 100ms
until the target is reached or until the measure voltage drops below
4.75V.  If the voltage does go too low, the target current is reduced
by 20mA and kept there.

This applies to currents selected automatically, or to values
set via sysfs.  So setting a large value will cause the maximum
available to be used - up to the limit of 1.7A imposed by the
hardware.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/power/twl4030_charger.c |   67 ---
 1 file changed, 61 insertions(+), 6 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 68117ad23564..2c537ee11bbe 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -119,6 +119,18 @@ struct twl4030_bci {
 #defineCHARGE_AUTO 1
 #defineCHARGE_LINEAR   2
 
+   /* When setting the USB current we slowly increase the
+* requested current until target is reached or the voltage
+* drops below 4.75V.  In the latter case we step back one
+* step.
+*/
+   unsigned intusb_cur_target;
+   struct delayed_work current_worker;
+#defineUSB_CUR_STEP2   /* 20mA at a time */
+#defineUSB_MIN_VOLT475 /* 4.75V */
+#defineUSB_CUR_DELAY   msecs_to_jiffies(100)
+#defineUSB_MAX_CURRENT 170 /* TWL4030 caps at 1.7A */
+
unsigned long   event;
 };
 
@@ -257,6 +269,12 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
} else {
cur = bci-usb_cur;
bci-ac_is_active = false;
+   if (cur  bci-usb_cur_target) {
+   cur = bci-usb_cur_target;
+   bci-usb_cur = cur;
+   }
+   if (cur  bci-usb_cur_target)
+   schedule_delayed_work(bci-current_worker, 
USB_CUR_DELAY);
}
 
/* First, check thresholds and see if cgain is needed */
@@ -391,6 +409,41 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
return 0;
 }
 
+static int twl4030_charger_get_current(void);
+
+static void twl4030_current_worker(struct work_struct *data)
+{
+   int v, curr;
+   int res;
+   struct twl4030_bci *bci = container_of(data, struct twl4030_bci,
+  current_worker.work);
+
+   res = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
+   if (res  0)
+   v = 0;
+   else
+   /* BCIVBUS uses ADCIN8, 7/1023 V/step */
+   v = res * 6843;
+   curr = twl4030_charger_get_current();
+
+   dev_dbg(bci-dev, v=%d cur=%d limit=%d target=%d\n, v, curr,
+   bci-usb_cur, bci-usb_cur_target);
+
+   if (v  USB_MIN_VOLT) {
+   /* Back up and stop adjusting. */
+   bci-usb_cur -= USB_CUR_STEP;
+   bci-usb_cur_target = bci-usb_cur;
+   } else if (bci-usb_cur = bci-usb_cur_target ||
+  bci-usb_cur + USB_CUR_STEP  USB_MAX_CURRENT) {
+   /* Reached target and voltage is OK - stop */
+   return;
+   } else {
+   bci-usb_cur += USB_CUR_STEP;
+   schedule_delayed_work(bci-current_worker, USB_CUR_DELAY);
+   }
+   twl4030_charger_update_current(bci);
+}
+
 /*
  * Enable/Disable USB Charge functionality.
  */
@@ -451,6 +504,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
pm_runtime_put_autosuspend(bci-transceiver-dev);
bci-usb_enabled = 0;
}
+   bci-usb_cur = 0;
}
 
return ret;
@@ -599,7 +653,7 @@ twl4030_bci_max_current_store(struct device *dev, struct 
device_attribute *attr,
if (dev == bci-ac-dev)
bci-ac_cur = cur;
else
-   bci-usb_cur = cur;
+   bci-usb_cur_target = cur;
 
twl4030_charger_update_current(bci);
return n;
@@ -621,7 +675,7 @@ static ssize_t twl4030_bci_max_current_show(struct device 
*dev,
cur = bci-ac_cur;
} else {
if (bci-ac_is_active)
-   cur = bci-usb_cur;
+   cur = bci-usb_cur_target;
}
if (cur  0) {
cur

[PATCH 10/13] twl4030_charger: add software controlled linear charging mode.

2015-07-29 Thread NeilBrown

Add a 'continuous' option for usb charging which enables
the linear charging mode of the twl4030.

Linear charging does a good job with not-so-reliable power sources.
Auto mode does not work well as it switches off when voltage drops
momentarily.  Care must be taken not to over-charge.

It was used with a bike hub dynamo since a year or so. In that case
there are automatically charging stops when the cyclist needs a break.

Original-by: Andreas Kemnade andr...@kemnade.info
Signed-off-by: NeilBrown n...@brown.name
---
 .../ABI/testing/sysfs-class-power-twl4030  |9 +++
 drivers/power/twl4030_charger.c|   55 ++--
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
index 40e0f919cbde..e8baa36aaa2b 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -24,3 +24,12 @@ Description:
auto - draw power as appropriate for detected
 power source and battery status.
off  - do not draw any power.
+   continuous
+  - activate mode described as linear in
+TWL data sheets.  This uses whatever
+current is available and doesn't switch off
+when voltage drops.
+
+This is useful for unstable power sources
+such as bicycle dynamo, but care should
+be taken that battery is not over-charged.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 6fa928ed3128..de5430deaf23 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -24,6 +24,8 @@
 #include linux/usb/otg.h
 #include linux/i2c/twl4030-madc.h
 
+#define TWL4030_BCIMDEN0x00
+#define TWL4030_BCIMDKEY   0x01
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
 #define TWL4030_BCIVAC 0x0a
@@ -35,13 +37,16 @@
 #define TWL4030_BCIIREF1   0x27
 #define TWL4030_BCIIREF2   0x28
 #define TWL4030_BCIMFKEY   0x11
+#define TWL4030_BCIMFEN3   0x14
 #define TWL4030_BCIMFTH8   0x1d
 #define TWL4030_BCIMFTH9   0x1e
+#define TWL4030_BCIWDKEY   0x21
 
 #define TWL4030_BCIMFSTS1  0x01
 
 #define TWL4030_BCIAUTOWEN BIT(5)
 #define TWL4030_CONFIG_DONEBIT(4)
+#define TWL4030_CVENAC BIT(2)
 #define TWL4030_BCIAUTOUSB BIT(1)
 #define TWL4030_BCIAUTOAC  BIT(0)
 #define TWL4030_CGAIN  BIT(5)
@@ -112,12 +117,13 @@ struct twl4030_bci {
int usb_mode; /* charging mode requested */
 #defineCHARGE_OFF  0
 #defineCHARGE_AUTO 1
+#defineCHARGE_LINEAR   2
 
unsigned long   event;
 };
 
 /* strings for 'usb_mode' values */
-static char *modes[] = { off, auto };
+static char *modes[] = { off, auto, continuous };
 
 /*
  * clear and set bits on an given register on a given module
@@ -404,16 +410,42 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
bci-usb_enabled = 1;
}
 
-   /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
-   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
-   if (ret  0)
-   return ret;
+   if (bci-usb_mode == CHARGE_AUTO)
+   /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
 
/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
+   if (bci-usb_mode == CHARGE_LINEAR) {
+   
twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0);
+   /* Watch dog key: WOVF acknowledge */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
+  TWL4030_BCIWDKEY);
+   /* 0x24 + EKEY6: off mode */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
+  TWL4030_BCIMDKEY);
+   /* EKEY2: Linear charge: USB path */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
+  TWL4030_BCIMDKEY);
+   /* WDKEY5: stop watchdog count */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
+  TWL4030_BCIWDKEY);
+   /* enable MFEN3 access */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c

Re: [PATCH 5/6] phy: twl4030-usb: add support for reading resistor on ID pin.

2015-06-01 Thread NeilBrown
On Mon, 1 Jun 2015 19:06:52 +0530 Kishon Vijay Abraham I kis...@ti.com
wrote:

 Hi,
 
 On Thursday 16 April 2015 01:33 PM, NeilBrown wrote:
  From: NeilBrown ne...@suse.de
 
  The twl4030 phy can measure, with low precision, the
  resistance-to-ground of the ID pin.
 
  Add a function to read the value, and export the result
  via sysfs.
 
 Little sceptical about adding new sysfs entries. Do you have a good reason to 
 add this?

The hardware can report the value, so why not present it to user-space?

I originally used this with a udev rule which would configure the maximum
current based on the resistance measure - to work with the particular charger
hardware I have.

More recent patches try to do all of the max-current configuration in the
kernel, so I could live without exporting the value via sysfs if that is a
show-stopper.

I can't see where the scepticism comes from though.  It is a well defined
and cleary documented feature of the hardware.  Why not expose it?

Thanks,
NeilBrown


 
 Thanks
 Kishon
 
  If the read fails, which it does sometimes, try again in 50msec.
 
  Acked-by: Pavel Machek pa...@ucw.cz
  Signed-off-by: NeilBrown ne...@suse.de
  ---
.../ABI/testing/sysfs-platform-twl4030-usb |   22 +++
drivers/phy/phy-twl4030-usb.c  |   63 
  
2 files changed, 85 insertions(+)
 
  diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb 
  b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
  index 512c51be64ae..425d23676f8a 100644
  --- a/Documentation/ABI/testing/sysfs-platform-twl4030-usb
  +++ b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
  @@ -6,3 +6,25 @@ Description:
  Possible values: on, off.
 
  Changes are notified via select/poll.
  +
  +What: /sys/bus/platform/devices/*twl4030-usb/id
  +Description:
  +   Read-only report on measurement of USB-OTG ID pin.
  +
  +   The ID pin may be floating, grounded, or pulled to
  +   ground by a resistor.
  +
  +   A very course grained reading of the resistance is
  +   available.  The numbers given in kilo-ohms are roughly
  +   the center-point of the detected range.
  +
  +   Possible values are:
  +   ground
  +   102k
  +   200k
  +   440k
  +   floating
  +   unknown
  +
  +   unknown indicates a problem with trying to detect
  +   the resistance.
  diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
  index 3a707dd14238..1d6f3e70193e 100644
  --- a/drivers/phy/phy-twl4030-usb.c
  +++ b/drivers/phy/phy-twl4030-usb.c
  @@ -379,6 +379,56 @@ static void twl4030_i2c_access(struct twl4030_usb 
  *twl, int on)
  }
}
 
  +enum twl4030_id_status {
  +   TWL4030_GROUND,
  +   TWL4030_102K,
  +   TWL4030_200K,
  +   TWL4030_440K,
  +   TWL4030_FLOATING,
  +   TWL4030_ID_UNKNOWN,
  +};
  +static char *twl4030_id_names[] = {
  +   ground,
  +   102k,
  +   200k,
  +   440k,
  +   floating,
  +   unknown
  +};
  +
  +enum twl4030_id_status twl4030_get_id(struct twl4030_usb *twl)
  +{
  +   int ret;
  +
  +   pm_runtime_get_sync(twl-dev);
  +   if (twl-usb_mode == T2_USB_MODE_ULPI)
  +   twl4030_i2c_access(twl, 1);
  +   ret = twl4030_usb_read(twl, ULPI_OTG_CTRL);
  +   if (ret  0 || !(ret  ULPI_OTG_ID_PULLUP)) {
  +   /* Need pull-up to read ID */
  +   twl4030_usb_set_bits(twl, ULPI_OTG_CTRL,
  +ULPI_OTG_ID_PULLUP);
  +   mdelay(50);
  +   }
  +   ret = twl4030_usb_read(twl, ID_STATUS);
  +   if (ret  0 || (ret  0x1f) == 0) {
  +   mdelay(50);
  +   ret = twl4030_usb_read(twl, ID_STATUS);
  +   }
  +
  +   if (twl-usb_mode == T2_USB_MODE_ULPI)
  +   twl4030_i2c_access(twl, 0);
  +   pm_runtime_put_autosuspend(twl-dev);
  +
  +   if (ret  0)
  +   return TWL4030_ID_UNKNOWN;
  +   ret = ffs(ret) - 1;
  +   if (ret  TWL4030_GROUND || ret  TWL4030_FLOATING)
  +   return TWL4030_ID_UNKNOWN;
  +
  +   return ret;
  +}
  +
static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
{
  u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
  @@ -532,6 +582,16 @@ static ssize_t twl4030_usb_vbus_show(struct device 
  *dev,
}
static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
 
  +static ssize_t twl4030_usb_id_show(struct device *dev,
  +  struct device_attribute *attr,
  +  char *buf)
  +{
  +   struct twl4030_usb *twl = dev_get_drvdata(dev);
  +   return scnprintf(buf, PAGE_SIZE, %s\n,
  +twl4030_id_names[twl4030_get_id(twl)]);
  +}
  +static DEVICE_ATTR(id, 0444, twl4030_usb_id_show, NULL);
  +
static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
  struct twl4030_usb *twl = _twl;
  @@ -709,6 +769,8 @@ static int twl4030_usb_probe(struct platform_device 
  *pdev)
  platform_set_drvdata(pdev, twl);
  if (device_create_file(pdev-dev, dev_attr_vbus

Re: [PATCH 4/6] phy: twl4030-usb: add ABI documentation

2015-04-17 Thread NeilBrown
On Sat, 18 Apr 2015 00:14:36 +0200 Pavel Machek pa...@ucw.cz wrote:

 On Thu 2015-04-16 18:03:04, NeilBrown wrote:
  From: NeilBrown ne...@suse.de
  
  This driver device one local attribute: vbus.
  Describe that in Documentation/ABI/testing/sysfs-platform/twl4030-usb.
  
  Signed-off-by: NeilBrown n...@brown.name
  ---
   .../ABI/testing/sysfs-platform-twl4030-usb |8 
   1 file changed, 8 insertions(+)
   create mode 100644 Documentation/ABI/testing/sysfs-platform-twl4030-usb
  
  diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb 
  b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
  new file mode 100644
  index ..512c51be64ae
  --- /dev/null
  +++ b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
  @@ -0,0 +1,8 @@
  +What: /sys/bus/platform/devices/*twl4030-usb/vbus
  +Description:
  +   Read-only status reporting if VBUS (approx 5V)
  +   is being supplied by the USB bus.
  +
  +   Possible values: on, off.
 
 Would bit be better to have values 0 and 1? Kernel usually does
 that for booleans...

1/ The code  already uses on and off, so changing would be an ABI
breakage.

2/ No it doesn't.
 For modules params, the kernel uses Y and N

  git grep '? on : off'  | wc

 find 172 matches.

NeilBrown


pgpMBx3gIbOQL.pgp
Description: OpenPGP digital signature


[PATCH 2/6] phy: twl4030-usb: remove pointless 'suspended' test in 'suspend' callback.

2015-04-16 Thread NeilBrown
When the runtime_suspend callback is running, 'runtime_status'
is always RPM_SUSPENDING, so pm_runtime_suspended() will always
fail.
Similarly while the runtime_resume callback is running
'runtime_status' is RPM_RESUMING, so pm_runtime_active() will
always fail.

So remove these two pointless tests.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/phy/phy-twl4030-usb.c |4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 3078f80bf520..590c2b1c1a94 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -396,8 +396,6 @@ static int twl4030_usb_runtime_suspend(struct device *dev)
struct twl4030_usb *twl = dev_get_drvdata(dev);
 
dev_dbg(twl-dev, %s\n, __func__);
-   if (pm_runtime_suspended(dev))
-   return 0;
 
__twl4030_phy_power(twl, 0);
regulator_disable(twl-usb1v5);
@@ -413,8 +411,6 @@ static int twl4030_usb_runtime_resume(struct device *dev)
int res;
 
dev_dbg(twl-dev, %s\n, __func__);
-   if (pm_runtime_active(dev))
-   return 0;
 
res = regulator_enable(twl-usb3v1);
if (res)


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/6] phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe function.

2015-04-16 Thread NeilBrown
The USB phy should initialize with power-off, and will be powered on
by the USB system when a cable connection is detected.

Having this pm_runtime_get_sync() during probe causes the phy to
*always* be powered on.
Removing it returns to sensible power management.

Fixes: 96be39ab34b77c6f6f5cd6ae03aac6c6449ee5c4
Signed-off-by: NeilBrown n...@brown.name
---
 drivers/phy/phy-twl4030-usb.c |1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 590c2b1c1a94..3a707dd14238 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -715,7 +715,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(pdev-dev);
pm_runtime_set_autosuspend_delay(pdev-dev, 2000);
pm_runtime_enable(pdev-dev);
-   pm_runtime_get_sync(pdev-dev);
 
/* Our job is to use irqs and status from the power module
 * to keep the transceiver disabled when nothing's connected.


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/6] phy: twl4030-usb: make runtime pm more reliable.

2015-04-16 Thread NeilBrown
From: NeilBrown ne...@suse.de

A construct like:

if (pm_runtime_suspended(twl-dev))
   pm_runtime_get_sync(twl-dev);

is against the spirit of the runtime_pm interface as it
makes the internal refcounting useless.

In this case it is also racy, particularly as 'put_autosuspend'
is used to drop a reference.
When that happens a timer is started and the device is
runtime-suspended after the timeout.
If the above code runs in this window, the device will not be
found to be suspended so no pm_runtime reference is taken.
When the timer expires the device will be suspended, which is
against the intention of the code.

So be more direct is taking and dropping references.
If twl-linkstat is VBUS_VALID or ID_GROUND, then hold a
pm_runtime reference, otherwise don't.
Define cable_present() to test for this condition.

Tested-by: Tony Lindgren t...@atomide.com
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/phy/phy-twl4030-usb.c |   29 -
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index bc42d6a8939f..3078f80bf520 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -144,6 +144,16 @@
 #define PMBR1  0x0D
 #define GPIO_USB_4PIN_ULPI_2430C   (3  0)
 
+/*
+ * If VBUS is valid or ID is ground, then we know a
+ * cable is present and we need to be runtime-enabled
+ */
+static inline bool cable_present(enum omap_musb_vbus_id_status stat)
+{
+   return stat == OMAP_MUSB_VBUS_VALID ||
+   stat == OMAP_MUSB_ID_GROUND;
+}
+
 struct twl4030_usb {
struct usb_phy  phy;
struct device   *dev;
@@ -536,8 +546,10 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 
mutex_lock(twl-lock);
if (status = 0  status != twl-linkstat) {
+   status_changed =
+   cable_present(twl-linkstat) !=
+   cable_present(status);
twl-linkstat = status;
-   status_changed = true;
}
mutex_unlock(twl-lock);
 
@@ -553,15 +565,11 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 * USB_LINK_VBUS state.  musb_hdrc won't care until it
 * starts to handle softconnect right.
 */
-   if ((status == OMAP_MUSB_VBUS_VALID) ||
-   (status == OMAP_MUSB_ID_GROUND)) {
-   if (pm_runtime_suspended(twl-dev))
-   pm_runtime_get_sync(twl-dev);
+   if (cable_present(status)) {
+   pm_runtime_get_sync(twl-dev);
} else {
-   if (pm_runtime_active(twl-dev)) {
-   pm_runtime_mark_last_busy(twl-dev);
-   pm_runtime_put_autosuspend(twl-dev);
-   }
+   pm_runtime_mark_last_busy(twl-dev);
+   pm_runtime_put_autosuspend(twl-dev);
}
omap_musb_mailbox(status);
}
@@ -767,6 +775,9 @@ static int twl4030_usb_remove(struct platform_device *pdev)
 
/* disable complete OTG block */
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+   if (cable_present(twl-linkstat))
+   pm_runtime_put_noidle(twl-dev);
pm_runtime_mark_last_busy(twl-dev);
pm_runtime_put(twl-dev);
 


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/6] phy: twl4030-usb: add support for reading resistor on ID pin.

2015-04-16 Thread NeilBrown
From: NeilBrown ne...@suse.de

The twl4030 phy can measure, with low precision, the
resistance-to-ground of the ID pin.

Add a function to read the value, and export the result
via sysfs.

If the read fails, which it does sometimes, try again in 50msec.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 .../ABI/testing/sysfs-platform-twl4030-usb |   22 +++
 drivers/phy/phy-twl4030-usb.c  |   63 
 2 files changed, 85 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb 
b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
index 512c51be64ae..425d23676f8a 100644
--- a/Documentation/ABI/testing/sysfs-platform-twl4030-usb
+++ b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
@@ -6,3 +6,25 @@ Description:
Possible values: on, off.
 
Changes are notified via select/poll.
+
+What: /sys/bus/platform/devices/*twl4030-usb/id
+Description:
+   Read-only report on measurement of USB-OTG ID pin.
+
+   The ID pin may be floating, grounded, or pulled to
+   ground by a resistor.
+
+   A very course grained reading of the resistance is
+   available.  The numbers given in kilo-ohms are roughly
+   the center-point of the detected range.
+
+   Possible values are:
+   ground
+   102k
+   200k
+   440k
+   floating
+   unknown
+
+   unknown indicates a problem with trying to detect
+   the resistance.
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 3a707dd14238..1d6f3e70193e 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -379,6 +379,56 @@ static void twl4030_i2c_access(struct twl4030_usb *twl, 
int on)
}
 }
 
+enum twl4030_id_status {
+   TWL4030_GROUND,
+   TWL4030_102K,
+   TWL4030_200K,
+   TWL4030_440K,
+   TWL4030_FLOATING,
+   TWL4030_ID_UNKNOWN,
+};
+static char *twl4030_id_names[] = {
+   ground,
+   102k,
+   200k,
+   440k,
+   floating,
+   unknown
+};
+
+enum twl4030_id_status twl4030_get_id(struct twl4030_usb *twl)
+{
+   int ret;
+
+   pm_runtime_get_sync(twl-dev);
+   if (twl-usb_mode == T2_USB_MODE_ULPI)
+   twl4030_i2c_access(twl, 1);
+   ret = twl4030_usb_read(twl, ULPI_OTG_CTRL);
+   if (ret  0 || !(ret  ULPI_OTG_ID_PULLUP)) {
+   /* Need pull-up to read ID */
+   twl4030_usb_set_bits(twl, ULPI_OTG_CTRL,
+ULPI_OTG_ID_PULLUP);
+   mdelay(50);
+   }
+   ret = twl4030_usb_read(twl, ID_STATUS);
+   if (ret  0 || (ret  0x1f) == 0) {
+   mdelay(50);
+   ret = twl4030_usb_read(twl, ID_STATUS);
+   }
+
+   if (twl-usb_mode == T2_USB_MODE_ULPI)
+   twl4030_i2c_access(twl, 0);
+   pm_runtime_put_autosuspend(twl-dev);
+
+   if (ret  0)
+   return TWL4030_ID_UNKNOWN;
+   ret = ffs(ret) - 1;
+   if (ret  TWL4030_GROUND || ret  TWL4030_FLOATING)
+   return TWL4030_ID_UNKNOWN;
+
+   return ret;
+}
+
 static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
 {
u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
@@ -532,6 +582,16 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
 }
 static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
 
+static ssize_t twl4030_usb_id_show(struct device *dev,
+  struct device_attribute *attr,
+  char *buf)
+{
+   struct twl4030_usb *twl = dev_get_drvdata(dev);
+   return scnprintf(buf, PAGE_SIZE, %s\n,
+twl4030_id_names[twl4030_get_id(twl)]);
+}
+static DEVICE_ATTR(id, 0444, twl4030_usb_id_show, NULL);
+
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
struct twl4030_usb *twl = _twl;
@@ -709,6 +769,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, twl);
if (device_create_file(pdev-dev, dev_attr_vbus))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(pdev-dev, dev_attr_id))
+   dev_warn(pdev-dev, could not create sysfs file\n);
 
ATOMIC_INIT_NOTIFIER_HEAD(twl-phy.notifier);
 
@@ -753,6 +815,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
pm_runtime_get_sync(twl-dev);
cancel_delayed_work(twl-id_workaround_work);
device_remove_file(twl-dev, dev_attr_vbus);
+   device_remove_file(twl-dev, dev_attr_id);
 
/* set transceiver mode to power on defaults */
twl4030_usb_set_mode(twl, -1);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/6] phy: twl4030-usb: add extcon to report cable connections.

2015-04-16 Thread NeilBrown
From: NeilBrown ne...@suse.de

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/phy/phy-twl4030-usb.c |   67 +
 1 file changed, 67 insertions(+)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 1d6f3e70193e..c42153d43ec2 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -40,6 +40,7 @@
 #include linux/regulator/consumer.h
 #include linux/err.h
 #include linux/slab.h
+#include linux/extcon.h
 
 /* Register defines */
 
@@ -173,6 +174,9 @@ struct twl4030_usb {
enum omap_musb_vbus_id_status linkstat;
boolvbus_supplied;
 
+   /* cable connection */
+   struct extcon_dev   edev;
+
struct delayed_work id_workaround_work;
 };
 
@@ -592,6 +596,54 @@ static ssize_t twl4030_usb_id_show(struct device *dev,
 }
 static DEVICE_ATTR(id, 0444, twl4030_usb_id_show, NULL);
 
+static const char *usb_cables[] = {
+   USB, /* id is floating */
+   Charger-downstream, /* id is floating and D+ shorted to D- */
+   USB-Host, /* id is ground */
+   USB-ACA, /* Accessory Charger Adapter id is something else */
+   NULL
+};
+enum {
+   TWL_CABLE_USB,
+   TWL_CABLE_CHARGER,  /* Not used - twl4030 can detect charger,
+* but driver cannot yet */
+   TWL_CABLE_OTG,
+   TWL_CABLE_ACA,
+};
+static u32 all_exclusive[] =  {0x, 0};
+
+static void twl4030_usb_report_cable(struct twl4030_usb *twl)
+{
+   enum twl4030_id_status sts;
+
+   if (!cable_present(twl-linkstat)) {
+   extcon_set_state(twl-edev, 0);
+   return;
+   }
+
+   sts = twl4030_get_id(twl);
+
+   switch (sts) {
+   case TWL4030_FLOATING: /* USB downstream */
+   extcon_update_state(twl-edev,
+   1TWL_CABLE_USB,
+   1TWL_CABLE_USB);
+   break;
+   case TWL4030_GROUND: /* USB host */
+   extcon_update_state(twl-edev,
+   1TWL_CABLE_OTG,
+   1TWL_CABLE_OTG);
+   break;
+   default: /* Some resistor */
+   extcon_update_state(twl-edev,
+   1TWL_CABLE_ACA,
+   1TWL_CABLE_ACA);
+   /* An ACA should set port to 'host' mode */
+   twl-linkstat = OMAP_MUSB_ID_GROUND;
+   break;
+   }
+}
+
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
struct twl4030_usb *twl = _twl;
@@ -628,6 +680,7 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
pm_runtime_put_autosuspend(twl-dev);
}
omap_musb_mailbox(status);
+   twl4030_usb_report_cable(twl);
}
 
/* don't schedule during sleep - irq works right then */
@@ -766,6 +819,20 @@ static int twl4030_usb_probe(struct platform_device *pdev)
}
usb_add_phy_dev(twl-phy);
 
+   twl-edev.name = devm_kasprintf(twl-dev, GFP_KERNEL, %s-usb,
+   dev_name(twl-dev-parent));
+   twl-edev.supported_cable = usb_cables;
+   twl-edev.mutually_exclusive = all_exclusive;
+   twl-edev.print_name = NULL; /* why would you change this? */
+   twl-edev.print_state = NULL; /* probably want to change this */
+
+   twl-edev.dev.parent = pdev-dev;
+   err = extcon_dev_register(twl-edev);
+   if (err) {
+   dev_err(pdev-dev, register extcon failed\n);
+   return err;
+   }
+
platform_set_drvdata(pdev, twl);
if (device_create_file(pdev-dev, dev_attr_vbus))
dev_warn(pdev-dev, could not create sysfs file\n);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/6] Enhancements to twl4030 phy to support better charging.

2015-04-16 Thread NeilBrown
Hi Kishon,
 this is a slightly modified version of the series I sent earlier.

 I've removed that patches which use the old 'notifier chain' and will
 solve the issue of communicating current available separately.

 I've added a couple of patches which fix some pm_runtime issues.

 In particular:
 phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe function.

 Fixes a bug which causes the usb phy to remain permanently powered
 on, hence the Cc to Tony.

 If these could be queued for some future merge window, I would really
 appreciate it.

Thanks,
NeilBrown


---

NeilBrown (6):
  phy: twl4030-usb: make runtime pm more reliable.
  phy: twl4030-usb: remove pointless 'suspended' test in 'suspend' callback.
  phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe 
function.
  phy: twl4030-usb: add ABI documentation
  phy: twl4030-usb: add support for reading resistor on ID pin.
  phy: twl4030-usb: add extcon to report cable connections.


 .../ABI/testing/sysfs-platform-twl4030-usb |   30 
 drivers/phy/phy-twl4030-usb.c  |  164 ++--
 2 files changed, 180 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-twl4030-usb

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/6] phy: twl4030-usb: add ABI documentation

2015-04-16 Thread NeilBrown
From: NeilBrown ne...@suse.de

This driver device one local attribute: vbus.
Describe that in Documentation/ABI/testing/sysfs-platform/twl4030-usb.

Signed-off-by: NeilBrown n...@brown.name
---
 .../ABI/testing/sysfs-platform-twl4030-usb |8 
 1 file changed, 8 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-twl4030-usb

diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb 
b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
new file mode 100644
index ..512c51be64ae
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
@@ -0,0 +1,8 @@
+What: /sys/bus/platform/devices/*twl4030-usb/vbus
+Description:
+   Read-only status reporting if VBUS (approx 5V)
+   is being supplied by the USB bus.
+
+   Possible values: on, off.
+
+   Changes are notified via select/poll.


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 13/14] twl4030_charger: Increase current carefully while watching voltage.

2015-03-29 Thread NeilBrown
On Mon, 23 Mar 2015 22:25:41 +0100 Pavel Machek pa...@ucw.cz wrote:

 Hi!
 
  The USB Battery Charging spec (BC1.2) suggests a dedicated
  charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25
  volts.
  
  To choose the correct current voltage setting requires a trial
  and error approach: try to draw current and see if the voltage drops
  too low.
  
  Even with a configured Standard Downstream Port, it may not be possible
  to reliably pull 500mA - depending on cable quality and source
  quality I have reports of charging failure due to the voltage dropping
  too low.
  
  To address both these concerns, this patch introduce incremental
  current setting.
  The current pull from VBUS is increased in steps of 20mA every 100ms
  until the target is reached or until the measure voltage drops below
  4.75V.  If the voltage does go too low, the target current is reduced
  by 20mA and kept there.
 
 Still nervous. If it is possible to overheat the charger, without
 tripping internal fuse, then you'll do it.

If it is possible to overheat the charger without tripping an internal fuse,
then sure the charger is mis-designed - is it not?

Can you suggest an algorithm for determining how much current can safely be
pulled from a charger that would *not* make you nervous?



 
  This applies to currents selected automatically, or to values
  set via sysfs.  So setting a large value will cause the maximum
  available to be used - up to the limit of 1.7A imposed by the
  hardware.
 
 
  +   printk(v=%d cur=%d target=%d\n, v, bci-usb_cur,
  +  bci-usb_cur_target);
 
 dev_info() and a bit better message, or drop it for production?

Changed to dev_dbg() - thanks.


 
  +   if (v  USB_MIN_VOLT) {
  +   /* Back up and stop adjusting. */
  +   bci-usb_cur -= USB_CUR_STEP;
  +   bci-usb_cur_target = bci-usb_cur;
 
 More importantly how does it work with device drawing power for
 operation, too?
 
 Imagine device need 500mA with wifi hotspot, nearly nothing while idle.
 
 Idle device. Code will find that it can charge using 1A, backs up to
 0.9A. User starts hotspot. Now device will draw 1.4A, overloading the
 charger and not charging at all...?

The current being measured and controlled is the current flowing in from the
USB VBUS, not flowing out to the battery.
So I the code choose 0.9A, that is all that will be drawn.

This is a possible issue similar to this though.
If the device is idle and the battery is fully charged, then it won't draw
much current from USB even if we allow it too.
So the algorithm might decide it is OK to draw 1.7A because at that time the
device cannot use more than 200mA, and that doesn't cause the voltage to drop.

Then later when user enabled wifi-hotspot, the current needed might go up
above what the charger can provide.

Maybe I should only increase the limit while the actual current is also
increasing.  Maybe also revisit the setting when the battery starts charging.

NeilBrown


 
 Best regards,
   Pavel



pgpc908HCllRF.pgp
Description: OpenPGP digital signature


Re: [PATCH 3/4] mmc: sdio: support switching to 1-bit before turning off clocks

2015-03-25 Thread NeilBrown
On Mon, 23 Mar 2015 10:10:18 +0100 Ulf Hansson ulf.hans...@linaro.org wrote:

 On 24 February 2015 at 03:42, NeilBrown ne...@suse.de wrote:

  @@ -941,8 +947,12 @@ void mmc_release_host(struct mmc_host *host)
 
  WARN_ON(!host-claimed);
 
  -   if (host-ops-disable  host-claim_cnt == 1)
  -   host-ops-disable(host);
  +   if (host-claim_cnt == 1) {
  +   if (atomic_read(host-sdio_narrowed) == 1)
  +   atomic_set(host-sdio_narrowed, 0);
  +   if (host-ops-disable)
  +   host-ops-disable(host);
  +   }
 
 As omap_hsmmc in currently the only user of the
 host_ops-enable|disable() callbacks, I wonder if this approach will
 work race-free for those hosts that don't implement these callbacks?

Hi Ulf,
 you might have guessed, but to be explicit: I withdraw this patchset.
I much prefer the other approach that I suggested using runtime PM on
the mmc_host device and switching to 1-bit more in the pm_runtime_suspend
function.

As you say, omap_hsmmc is the only user of enable/disable and they were an
important part of my strategy in this patchset.
Which raises the question:  what is omap_hsmmc using enable/disable?

My guess is that it is largely historical - added because omap_hsmmc wanted
runtime pm before sufficient generic infrastructure was available.

I've tested a patch to remove it, and it seem fine.  I'll post it.

Thanks,
NeilBrown



pgp_36U6si_xZ.pgp
Description: OpenPGP digital signature


[PATCH 2/2] mmc: remove enable/disable methods.

2015-03-25 Thread NeilBrown
The 'enable' and 'disable' methods are deprecated
according to host.h, and are no longer used.  So
discard them.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/core/core.c  |5 -
 include/linux/mmc/host.h |6 --
 2 files changed, 11 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 23f10f72e5f3..709ada9f26b5 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -920,8 +920,6 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
wake_up(host-wq);
spin_unlock_irqrestore(host-lock, flags);
remove_wait_queue(host-wq, wait);
-   if (host-ops-enable  !stop  host-claim_cnt == 1)
-   host-ops-enable(host);
return stop;
 }
 
@@ -940,9 +938,6 @@ void mmc_release_host(struct mmc_host *host)
 
WARN_ON(!host-claimed);
 
-   if (host-ops-disable  host-claim_cnt == 1)
-   host-ops-disable(host);
-
spin_lock_irqsave(host-lock, flags);
if (--host-claim_cnt) {
/* Release for nested claim */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0c8cbe5d1550..b5bedaec6223 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -80,12 +80,6 @@ struct mmc_ios {
 
 struct mmc_host_ops {
/*
-* 'enable' is called when the host is claimed and 'disable' is called
-* when the host is released. 'enable' and 'disable' are deprecated.
-*/
-   int (*enable)(struct mmc_host *host);
-   int (*disable)(struct mmc_host *host);
-   /*
 * It is optional for the host to implement pre_req and post_req in
 * order to support double buffering of requests (prepare one
 * request while another request is active).


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] mmc: omap_hsmmc: stop using .enable and .disable method.

2015-03-25 Thread NeilBrown
enable and disable are only used to get and put
runtime pm references.  .set_ios already does this
itself, and other drivers just do it in set_ios
and .request without using enable/disable.

So add pm_runtime get/put to omap_hsmmc_request(),
and discard the enable/disable methods.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/host/omap_hsmmc.c |   24 +++-
 1 file changed, 3 insertions(+), 21 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f84cfb01716d..092bcecd73e6 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -882,6 +882,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host 
*host, struct mmc_req
return;
host-mrq = NULL;
mmc_request_done(host-mmc, mrq);
+   pm_runtime_mark_last_busy(host-dev);
+   pm_runtime_put_autosuspend(host-dev);
 }
 
 /*
@@ -1537,6 +1539,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, 
struct mmc_request *req)
 
BUG_ON(host-req_in_progress);
BUG_ON(host-dma_ch != -1);
+   pm_runtime_get_sync(host-dev);
if (host-protect_card) {
if (host-reqs_blocked  3) {
/*
@@ -1778,25 +1781,6 @@ static void omap_hsmmc_conf_bus_power(struct 
omap_hsmmc_host *host)
set_sd_bus_power(host);
 }
 
-static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
-{
-   struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-   pm_runtime_get_sync(host-dev);
-
-   return 0;
-}
-
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
-{
-   struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-   pm_runtime_mark_last_busy(host-dev);
-   pm_runtime_put_autosuspend(host-dev);
-
-   return 0;
-}
-
 static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
 unsigned int direction, int blk_size)
 {
@@ -1808,8 +1792,6 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card 
*card,
 }
 
 static struct mmc_host_ops omap_hsmmc_ops = {
-   .enable = omap_hsmmc_enable_fclk,
-   .disable = omap_hsmmc_disable_fclk,
.post_req = omap_hsmmc_post_req,
.pre_req = omap_hsmmc_pre_req,
.request = omap_hsmmc_request,


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/2] Remove mmc_host enable/disable methods.

2015-03-25 Thread NeilBrown
Only omap_hsmmc uses enable and disable, and this seems
to be largely for historical reasons and is no longer
necessary.

I have tested these patches with an OMAP3 with an
uSD card on mmc0 and a wifi SDIO device on mmc1.

NeilBrown


---

NeilBrown (2):
  mmc: omap_hsmmc: stop using .enable and .disable method.
  mmc: remove enable/disable methods.


 drivers/mmc/core/core.c   |5 -
 drivers/mmc/host/omap_hsmmc.c |   24 +++-
 include/linux/mmc/host.h  |6 --
 3 files changed, 3 insertions(+), 32 deletions(-)

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] mmc: omap_hsmmc: stop using .enable and .disable method.

2015-03-25 Thread NeilBrown
On Thu, 26 Mar 2015 08:43:37 +1100 NeilBrown n...@brown.name wrote:

 enable and disable are only used to get and put
 runtime pm references.  .set_ios already does this
 itself, and other drivers just do it in set_ios
 and .request without using enable/disable.
 
 So add pm_runtime get/put to omap_hsmmc_request(),
 and discard the enable/disable methods.
 
 Signed-off-by: NeilBrown n...@brown.name

Sorry, that patch wasn't much good.  This one I have really tested properly
and checked that the 'put' match the 'get's and  that the device to regularly
go to sleep as expected.

NeilBrown


From: NeilBrown n...@brown.name
Date: Thu, 26 Mar 2015 08:28:43 +1100
Subject: [PATCH] mmc: omap_hsmmc: stop using .enable and .disable method.

enable and disable are only used to get and put
runtime pm references.  .set_ios already does this
itself, and other drivers just do it in set_ios
and .request without using enable/disable.

So add pm_runtime get/put to omap_hsmmc_request(),
and discard the enable/disable methods.

Signed-off-by: NeilBrown n...@brown.name

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f84cfb01716d..2cb81538a612 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -882,6 +882,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host 
*host, struct mmc_req
return;
host-mrq = NULL;
mmc_request_done(host-mmc, mrq);
+   pm_runtime_mark_last_busy(host-dev);
+   pm_runtime_put_autosuspend(host-dev);
 }
 
 /*
@@ -1305,6 +1307,8 @@ static void omap_hsmmc_dma_callback(void *param)
 
host-mrq = NULL;
mmc_request_done(host-mmc, mrq);
+   pm_runtime_mark_last_busy(host-dev);
+   pm_runtime_put_autosuspend(host-dev);
}
 }
 
@@ -1537,6 +1541,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, 
struct mmc_request *req)
 
BUG_ON(host-req_in_progress);
BUG_ON(host-dma_ch != -1);
+   pm_runtime_get_sync(host-dev);
if (host-protect_card) {
if (host-reqs_blocked  3) {
/*
@@ -1553,6 +1558,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, 
struct mmc_request *req)
req-data-error = -EBADF;
req-cmd-retries = 0;
mmc_request_done(mmc, req);
+   pm_runtime_mark_last_busy(host-dev);
+   pm_runtime_put_autosuspend(host-dev);
return;
} else if (host-reqs_blocked)
host-reqs_blocked = 0;
@@ -1566,6 +1573,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, 
struct mmc_request *req)
req-data-error = err;
host-mrq = NULL;
mmc_request_done(mmc, req);
+   pm_runtime_mark_last_busy(host-dev);
+   pm_runtime_put_autosuspend(host-dev);
return;
}
if (req-sbc  !(host-flags  AUTO_CMD23)) {
@@ -1778,25 +1787,6 @@ static void omap_hsmmc_conf_bus_power(struct 
omap_hsmmc_host *host)
set_sd_bus_power(host);
 }
 
-static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
-{
-   struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-   pm_runtime_get_sync(host-dev);
-
-   return 0;
-}
-
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
-{
-   struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-   pm_runtime_mark_last_busy(host-dev);
-   pm_runtime_put_autosuspend(host-dev);
-
-   return 0;
-}
-
 static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
 unsigned int direction, int blk_size)
 {
@@ -1808,8 +1798,6 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card 
*card,
 }
 
 static struct mmc_host_ops omap_hsmmc_ops = {
-   .enable = omap_hsmmc_enable_fclk,
-   .disable = omap_hsmmc_disable_fclk,
.post_req = omap_hsmmc_post_req,
.pre_req = omap_hsmmc_pre_req,
.request = omap_hsmmc_request,


pgpHruKccfCsN.pgp
Description: OpenPGP digital signature


[PATCH 09/14] twl4030_charger: only draw USB current as negotiated with host.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

If the phy has been told what current it can draw, it tells us
and now we use that number.

Note that 'vbus_draw' is in mA, while usb_cur is in uA.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index df031b0123d0..2042e7619954 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -602,6 +602,7 @@ static void twl4030_bci_usb_work(struct work_struct *data)
switch (bci-event) {
case USB_EVENT_VBUS:
case USB_EVENT_CHARGER:
+   case USB_EVENT_ENUMERATED:
twl4030_charger_enable_usb(bci, true);
break;
case USB_EVENT_NONE:
@@ -614,6 +615,7 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
   void *priv)
 {
struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, usb_nb);
+   unsigned int *vbus_draw = priv;
 
dev_dbg(bci-dev, OTG notify %lu\n, val);
 
@@ -624,6 +626,9 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
bci-usb_cur = 10;
 
bci-event = val;
+   if (val == USB_EVENT_ENUMERATED  vbus_draw 
+   *vbus_draw * 1000  bci-usb_cur)
+   bci-usb_cur = *vbus_draw * 1000;
schedule_work(bci-work);
 
return NOTIFY_OK;


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [Gta04-owner] [PATCH 3/4] usb: phy: twl4030: add support for reading restore on ID pin.

2015-03-22 Thread NeilBrown
On Wed, 4 Mar 2015 07:54:41 +0100 Dr. H. Nikolaus Schaller
h...@goldelico.com wrote:

 
 Am 04.03.2015 um 07:35 schrieb NeilBrown ne...@suse.de:
 
  On Mon, 2 Mar 2015 22:04:31 +0100 Pavel Machek pa...@ucw.cz wrote:
  
  Hi!
  
  The twl4030 phy can measure, with low precision, the
  resistance-to-ground of the ID pin.
  
  Add a function to read the value, and export the result
  via sysfs.
  
  If the read fails, which it does sometimes, try again in 50msec.
  
  Signed-off-by: NeilBrown ne...@suse.de
  ---
  drivers/phy/phy-twl4030-usb.c |   63 
  +
  1 file changed, 63 insertions(+)
  
  diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
  index 023fe150c7a1..759950898df9 100644
  --- a/drivers/phy/phy-twl4030-usb.c
  +++ b/drivers/phy/phy-twl4030-usb.c
  @@ -374,6 +374,56 @@ static void twl4030_i2c_access(struct twl4030_usb 
  *twl, int on)
}
  }
  
  +enum twl4030_id_status {
  + TWL4030_GROUND,
  + TWL4030_102K,
  + TWL4030_200K,
  + TWL4030_440K,
  + TWL4030_FLOATING,
  + TWL4030_ID_UNKNOWN,
  +};
  +static char *twl4030_id_names[] = {
  + ground,
  + 102k,
  + 200k,
  + 440k,
  
  New /sys files should be documented somewhere...?
  
  Preferably with the code...
  
  
  Does it make sense to change 440k - 440KOhm?
  
  Interesting question.  I prefer to avoid including units in files - bare
  numbers is better.  But there is no number to match floating unless I 
  spell
  it out as infinity, and wouldn't be helpful.
  
  Certainly K would be preferred over k“,
 
 The international standard for kilo = 1000 is a lower case k.
 While it is (non-standard) to use K for 1024:
 
 http://en.wikipedia.org/wiki/Kilobyte
 
 So I would keep the string constants lower case to avoid this potential 
 confusion.

Yes, I got that backwards, didn't I.

I think I'll leave it as lower-case.
I won't include the word ohm - it is very uncommon to have units explicit
in sysfs attribute values.

Thanks,
NeilBrown


pgpTfJsV9eFf0.pgp
Description: OpenPGP digital signature


[PATCH 03/14] twl4030_charger: use runtime_pm to keep usb phy active while charging.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

The twl4030 usb phy needs to be active while we are using
the USB VBUS as a current source for charging.
In particular, the usb3v1 regulator must be enabled and the
PHY_PWR_PHYPWD bit must be set to keep the phy powered.

commit ab37813f4093a5f59cb8e083cde277289dc72ed3
twl4030_charger: Allow charger to control the regulator that feeds it

Gave the charger control over the regulator, but didn't resolve
the PHY_PWR_PHYPWD issue.

Now that both of these are controlled by runtime_pm in
phy-twl4030-usb, we can simply take a runtime_pm reference to the USB
phy whenever the charger wants to use it as a current source.

So this patch reverts the above commit, and adds the necessary
runtime_pm calls.

Acked-by: Lee Jones lee.jo...@linaro.org
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/mfd/twl-core.c  |9 -
 drivers/power/twl4030_charger.c |   18 +-
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 489674a2497e..831696ee2472 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -788,9 +788,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
static struct regulator_consumer_supply usb1v8 = {
.supply =   usb1v8,
};
-   static struct regulator_consumer_supply usb3v1[] = {
-   { .supply = usb3v1 },
-   { .supply = bci3v1 },
+   static struct regulator_consumer_supply usb3v1 = {
+   .supply =   usb3v1,
};
 
/* First add the regulators so that they can be used by transceiver */
@@ -818,7 +817,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
return PTR_ERR(child);
 
child = add_regulator_linked(TWL4030_REG_VUSB3V1,
- usb_fixed, usb3v1, 2,
+ usb_fixed, usb3v1, 1,
  features);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -838,7 +837,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)  child) {
usb1v5.dev_name = dev_name(child);
usb1v8.dev_name = dev_name(child);
-   usb3v1[0].dev_name = dev_name(child);
+   usb3v1.dev_name = dev_name(child);
}
}
 
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 7b6c4000cd30..94c7a4d9400a 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,7 +22,6 @@
 #include linux/power_supply.h
 #include linux/notifier.h
 #include linux/usb/otg.h
-#include linux/regulator/machine.h
 
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
@@ -94,7 +93,6 @@ struct twl4030_bci {
struct work_struct  work;
int irq_chg;
int irq_bci;
-   struct regulator*usb_reg;
int usb_enabled;
 
unsigned long   event;
@@ -208,7 +206,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 {
int ret;
 
-   if (enable) {
+   if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
/* Check for USB charger connected */
if (!twl4030_bci_have_vbus(bci))
return -ENODEV;
@@ -222,14 +220,9 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
return -EACCES;
}
 
-   /* Need to keep regulator on */
+   /* Need to keep phy powered */
if (!bci-usb_enabled) {
-   ret = regulator_enable(bci-usb_reg);
-   if (ret) {
-   dev_err(bci-dev,
-   Failed to enable regulator\n);
-   return ret;
-   }
+   pm_runtime_get_sync(bci-transceiver-dev);
bci-usb_enabled = 1;
}
 
@@ -244,7 +237,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
} else {
ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
if (bci-usb_enabled) {
-   regulator_disable(bci-usb_reg);
+   pm_runtime_mark_last_busy(bci-transceiver-dev);
+   pm_runtime_put_autosuspend(bci-transceiver-dev);
bci-usb_enabled = 0;
}
}
@@ -602,8 +596,6 @@ static int

[PATCH 02/14] twl4030_charger: use devres for power_supply_register and kzalloc.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

Final allocations/registrations are now managed by devres.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   32 +---
 1 file changed, 9 insertions(+), 23 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 58996d252ecf..7b6c4000cd30 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -565,7 +565,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
int ret;
u32 reg;
 
-   bci = kzalloc(sizeof(*bci), GFP_KERNEL);
+   bci = devm_kzalloc(pdev-dev, sizeof(*bci), GFP_KERNEL);
if (bci == NULL)
return -ENOMEM;
 
@@ -580,7 +580,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
ret = twl4030_is_battery_present(bci);
if  (ret) {
dev_crit(pdev-dev, Battery was not detected:%d\n, ret);
-   goto fail_no_battery;
+   return ret;
}
 
platform_set_drvdata(pdev, bci);
@@ -590,10 +590,10 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
bci-ac.num_properties = ARRAY_SIZE(twl4030_charger_props);
bci-ac.get_property = twl4030_bci_get_property;
 
-   ret = power_supply_register(pdev-dev, bci-ac);
+   ret = devm_power_supply_register(pdev-dev, bci-ac);
if (ret) {
dev_err(pdev-dev, failed to register ac: %d\n, ret);
-   goto fail_register_ac;
+   return ret;
}
 
bci-usb.name = twl4030_usb;
@@ -604,10 +604,10 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
 
bci-usb_reg = regulator_get(bci-dev, bci3v1);
 
-   ret = power_supply_register(pdev-dev, bci-usb);
+   ret = devm_power_supply_register(pdev-dev, bci-usb);
if (ret) {
dev_err(pdev-dev, failed to register usb: %d\n, ret);
-   goto fail_register_usb;
+   return ret;
}
 
ret = devm_request_threaded_irq(pdev-dev, bci-irq_chg, NULL,
@@ -616,7 +616,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
if (ret  0) {
dev_err(pdev-dev, could not request irq %d, status %d\n,
bci-irq_chg, ret);
-   goto fail;
+   return ret;
}
 
ret = devm_request_threaded_irq(pdev-dev, bci-irq_bci, NULL,
@@ -624,7 +624,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
if (ret  0) {
dev_err(pdev-dev, could not request irq %d, status %d\n,
bci-irq_bci, ret);
-   goto fail;
+   return ret;
}
 
INIT_WORK(bci-work, twl4030_bci_usb_work);
@@ -647,7 +647,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
   TWL4030_INTERRUPTS_BCIIMR1A);
if (ret  0) {
dev_err(pdev-dev, failed to unmask interrupts: %d\n, ret);
-   goto fail;
+   return ret;
}
 
reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
@@ -665,16 +665,6 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
twl4030_charger_enable_backup(0, 0);
 
return 0;
-
-fail:
-   power_supply_unregister(bci-usb);
-fail_register_usb:
-   power_supply_unregister(bci-ac);
-fail_register_ac:
-fail_no_battery:
-   kfree(bci);
-
-   return ret;
 }
 
 static int __exit twl4030_bci_remove(struct platform_device *pdev)
@@ -691,10 +681,6 @@ static int __exit twl4030_bci_remove(struct 
platform_device *pdev)
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR2A);
 
-   power_supply_unregister(bci-usb);
-   power_supply_unregister(bci-ac);
-   kfree(bci);
-
return 0;
 }
 


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 06/14] twl4030_charger: allow fine control of charger current.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

The twl4030 allows control of the incoming current.
Part of this control is a 'CGAIN' setting which doubles
the range for half the precision.  This control affects
several different current setting, so all need to be updated
at once when CGAIN is changed.

With this patch, all of these current setting are managed
by the driver, but most are left at their default settings.

The current drawn is set to 500mA if the allow_usb module parameter is
set, and to 100mA otherwise.
More fine control will appear in later patches.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |  168 +--
 1 file changed, 160 insertions(+), 8 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index c9a7efbb9141..02d677ef63e2 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -31,6 +31,11 @@
 #define TWL4030_BCIMFSTS4  0x10
 #define TWL4030_BCICTL10x23
 #define TWL4030_BB_CFG 0x12
+#define TWL4030_BCIIREF1   0x27
+#define TWL4030_BCIIREF2   0x28
+#define TWL4030_BCIMFKEY   0x11
+#define TWL4030_BCIMFTH8   0x1d
+#define TWL4030_BCIMFTH9   0x1e
 
 #define TWL4030_BCIMFSTS1  0x01
 
@@ -95,6 +100,12 @@ struct twl4030_bci {
int irq_bci;
int usb_enabled;
 
+   /*
+* ichg values in uA. If any are 'large', we set CGAIN to
+* '1' which doubles the range for half the precision.
+*/
+   unsigned intichg_eoc, ichg_lo, ichg_hi, cur;
+
unsigned long   event;
 };
 
@@ -211,6 +222,146 @@ static int ua2regval(int ua, bool cgain)
return ret;
 }
 
+static int twl4030_charger_update_current(struct twl4030_bci *bci)
+{
+   int status;
+   unsigned reg, cur_reg;
+   u8 bcictl1, oldreg, fullreg;
+   bool cgain = false;
+   u8 boot_bci;
+
+   /* First, check thresholds and see if cgain is needed */
+   if (bci-ichg_eoc = 20)
+   cgain = true;
+   if (bci-ichg_lo = 40)
+   cgain = true;
+   if (bci-ichg_hi = 82)
+   cgain = true;
+   if (bci-cur  852000)
+   cgain = true;
+
+   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
+   if (status  0)
+   return status;
+   if (twl_i2c_read_u8(TWL_MODULE_PM_MASTER, boot_bci,
+   TWL4030_PM_MASTER_BOOT_BCI)  0)
+   boot_bci = 0;
+   boot_bci = 7;
+
+   if ((!!cgain) != !!(bcictl1  TWL4030_CGAIN))
+   /* Need to turn for charging while we change the
+* CGAIN bit.  Leave it off while everything is
+* updated.
+*/
+   twl4030_clear_set_boot_bci(boot_bci, 0);
+
+   /*
+* For ichg_eoc, the hardware only supports reg values matching
+* 100000, and requires the  be stored in the high nibble
+* of TWL4030_BCIMFTH8
+*/
+   reg = ua2regval(bci-ichg_eoc, cgain);
+   if (reg  0x278)
+   reg = 0x278;
+   if (reg  0x200)
+   reg = 0x200;
+   reg = (reg  3)  0xf;
+   fullreg = reg  4;
+
+   /*
+* For ichg_lo, reg value must match 10.
+*  is stored in low nibble of TWL4030_BCIMFTH8
+*/
+   reg = ua2regval(bci-ichg_lo, cgain);
+   if (reg  0x2F0)
+   reg = 0x2F0;
+   if (reg  0x200)
+   reg = 0x200;
+   reg = (reg  4)  0xf;
+   fullreg |= reg;
+
+   /* ichg_eoc and ichg_lo live in same register */
+   status = twl4030_bci_read(TWL4030_BCIMFTH8, oldreg);
+   if (status  0)
+   return status;
+   if (oldreg != fullreg) {
+   status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xF4,
+ TWL4030_BCIMFKEY);
+   if (status  0)
+   return status;
+   twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+fullreg, TWL4030_BCIMFTH8);
+   }
+
+   /* ichg_hi threshold must be 101100 (I think) */
+   reg = ua2regval(bci-ichg_hi, cgain);
+   if (reg  0x3E0)
+   reg = 0x3E0;
+   if (reg  0x200)
+   reg = 0x200;
+   fullreg = (reg  5)  0xF;
+   fullreg = 4;
+   status = twl4030_bci_read(TWL4030_BCIMFTH9, oldreg);
+   if (status  0)
+   return status;
+   if ((oldreg  0xF0) != fullreg) {
+   fullreg |= (oldreg  0x0F);
+   status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7,
+ TWL4030_BCIMFKEY);
+   if (status  0)
+   return status;
+   twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+fullreg, TWL4030_BCIMFTH9

[PATCH 05/14] twl4030_charger: split uA calculation into a function.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

We will need this calculation in other places, so
create functions to map between register value and uA value.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   48 ---
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 0e62a5ae56a3..c9a7efbb9141 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -178,6 +178,40 @@ static int twl4030_is_battery_present(struct twl4030_bci 
*bci)
 }
 
 /*
+ * TI provided formulas:
+ * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
+ * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
+ * Here we use integer approximation of:
+ * CGAIN == 0: val * 1.6618 - 0.85 * 1000
+ * CGAIN == 1: (val * 1.6618 - 0.85 * 1000) * 2
+ */
+/*
+ * convert twl register value for currents into uA
+ */
+static int regval2ua(int regval, bool cgain)
+{
+   if (cgain)
+   return (regval * 16618 - 8500 * 1000) / 5;
+   else
+   return (regval * 16618 - 8500 * 1000) / 10;
+}
+
+/*
+ * convert uA currents into twl register value
+ */
+static int ua2regval(int ua, bool cgain)
+{
+   int ret;
+   if (cgain)
+   ua /= 2;
+   ret = (ua * 10 + 8500 * 1000) / 16618;
+   /* rounding problems */
+   if (ret  512)
+   ret = 512;
+   return ret;
+}
+
+/*
  * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
@@ -366,14 +400,6 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
return NOTIFY_OK;
 }
 
-/*
- * TI provided formulas:
- * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
- * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
- * Here we use integer approximation of:
- * CGAIN == 0: val * 1.6618 - 0.85
- * CGAIN == 1: (val * 1.6618 - 0.85) * 2
- */
 static int twl4030_charger_get_current(void)
 {
int curr;
@@ -388,11 +414,7 @@ static int twl4030_charger_get_current(void)
if (ret)
return ret;
 
-   ret = (curr * 16618 - 850 * 1) / 10;
-   if (bcictl1  TWL4030_CGAIN)
-   ret *= 2;
-
-   return ret;
+   return regval2ua(curr, bcictl1  TWL4030_CGAIN);
 }
 
 /*


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 04/14] twl4030_charger: trust phy to determine when USB power is available.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

The usb phy driver already determines when VBUS is available,
so repeating the test in the charger driver is pointless duplication.

On probe, process the last event from the phy, and from then on,
do whatever the phy tells us without double-checking.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   33 ++---
 1 file changed, 6 insertions(+), 27 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 94c7a4d9400a..0e62a5ae56a3 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -178,28 +178,6 @@ static int twl4030_is_battery_present(struct twl4030_bci 
*bci)
 }
 
 /*
- * Check if VBUS power is present
- */
-static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
-{
-   int ret;
-   u8 hwsts;
-
-   ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, hwsts,
- TWL4030_PM_MASTER_STS_HW_CONDITIONS);
-   if (ret  0)
-   return 0;
-
-   dev_dbg(bci-dev, check_vbus: HW_CONDITIONS %02x\n, hwsts);
-
-   /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */
-   if ((hwsts  TWL4030_STS_VBUS)  !(hwsts  TWL4030_STS_USB_ID))
-   return 1;
-
-   return 0;
-}
-
-/*
  * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
@@ -207,10 +185,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
int ret;
 
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
-   /* Check for USB charger connected */
-   if (!twl4030_bci_have_vbus(bci))
-   return -ENODEV;
-
/*
 * Until we can find out what current the device can provide,
 * require a module param to enable USB charging.
@@ -649,7 +623,12 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
dev_warn(pdev-dev, failed to unmask interrupts: %d\n, ret);
 
twl4030_charger_enable_ac(true);
-   twl4030_charger_enable_usb(bci, true);
+   if (!IS_ERR_OR_NULL(bci-transceiver))
+   twl4030_bci_usb_ncb(bci-usb_nb,
+   bci-transceiver-last_event,
+   NULL);
+   else
+   twl4030_charger_enable_usb(bci, false);
if (pdata)
twl4030_charger_enable_backup(pdata-bb_uvolt,
  pdata-bb_uamp);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 11/14] twl4030_charger: add software controlled linear charging mode.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

Add a 'continuous' option for usb charging which enables
the linear charging mode of the twl4030.

Linear charging does a good job with not-so-reliable power sources.
Auto mode does not work well as it switches off when voltage drops
momentarily.  Care must be taken not to over-charge.

It was used with a bike hub dynamo since a year or so. In that case
there are automatically charging stops when the cyclist needs a break.

Orignal-by: Andreas Kemnade andr...@kemnade.info
Signed-off-by: NeilBrown ne...@suse.de
---
 .../ABI/testing/sysfs-class-power-twl4030  |9 +++
 drivers/power/twl4030_charger.c|   55 ++--
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
index 390db7a55231..c27e8ca8c9db 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -24,3 +24,12 @@ Description:
auto - draw power as appropriate for detected
 power source and battery status.
off  - do not draw any power.
+   continuous
+  - activate mode described as linear in
+TWL data sheets.  This uses whatever
+current is available and doesn't switch off
+when voltage drops.
+
+This is useful for unstable power sources
+such as bicycle dynamo, but care should
+be taken that battery is not over-charged.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 802cdd6d3e00..2c8d85102def 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -24,6 +24,8 @@
 #include linux/usb/otg.h
 #include linux/i2c/twl4030-madc.h
 
+#define TWL4030_BCIMDEN0x00
+#define TWL4030_BCIMDKEY   0x01
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
 #define TWL4030_BCIVAC 0x0a
@@ -35,13 +37,16 @@
 #define TWL4030_BCIIREF1   0x27
 #define TWL4030_BCIIREF2   0x28
 #define TWL4030_BCIMFKEY   0x11
+#define TWL4030_BCIMFEN3   0x14
 #define TWL4030_BCIMFTH8   0x1d
 #define TWL4030_BCIMFTH9   0x1e
+#define TWL4030_BCIWDKEY   0x21
 
 #define TWL4030_BCIMFSTS1  0x01
 
 #define TWL4030_BCIAUTOWEN BIT(5)
 #define TWL4030_CONFIG_DONEBIT(4)
+#define TWL4030_CVENAC BIT(2)
 #define TWL4030_BCIAUTOUSB BIT(1)
 #define TWL4030_BCIAUTOAC  BIT(0)
 #define TWL4030_CGAIN  BIT(5)
@@ -112,12 +117,13 @@ struct twl4030_bci {
int usb_mode; /* charging mode requested */
 #defineCHARGE_OFF  0
 #defineCHARGE_AUTO 1
+#defineCHARGE_LINEAR   2
 
unsigned long   event;
 };
 
 /* strings for 'usb_mode' values */
-static char *modes[] = { off, auto };
+static char *modes[] = { off, auto, continuous };
 
 /*
  * clear and set bits on an given register on a given module
@@ -404,16 +410,42 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
bci-usb_enabled = 1;
}
 
-   /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
-   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
-   if (ret  0)
-   return ret;
+   if (bci-usb_mode == CHARGE_AUTO)
+   /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
 
/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
+   if (bci-usb_mode == CHARGE_LINEAR) {
+   
twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0);
+   /* Watch dog key: WOVF acknowledge */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
+  TWL4030_BCIWDKEY);
+   /* 0x24 + EKEY6: off mode */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
+  TWL4030_BCIMDKEY);
+   /* EKEY2: Linear charge: USB path */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
+  TWL4030_BCIMDKEY);
+   /* WDKEY5: stop watchdog count */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
+  TWL4030_BCIWDKEY);
+   /* enable MFEN3 access */
+   ret = twl_i2c_write_u8

[PATCH 14/14] twl4030_charger: assume a 'charger' can supply maximum current.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

If it cannot, we will stop pulling more current when voltage drops.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index d0199495dddc..6f0dc971d84d 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -694,8 +694,10 @@ static void twl4030_bci_usb_work(struct work_struct *data)
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
 
switch (bci-event) {
-   case USB_EVENT_VBUS:
case USB_EVENT_CHARGER:
+   bci-usb_cur = USB_MAX_CURRENT;
+   /* FALL THROUGH */
+   case USB_EVENT_VBUS:
case USB_EVENT_ENUMERATED:
twl4030_charger_enable_usb(bci, true);
break;


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 13/15] twl4030_charger: add ac/mode to match usb/mode

2015-03-22 Thread NeilBrown
On Fri, 6 Mar 2015 23:59:04 +0200 Grazvydas Ignotas nota...@gmail.com wrote:

 On Tue, Feb 24, 2015 at 6:33 AM, NeilBrown ne...@suse.de wrote:
  This allows AC charging to be turned off, much like usb charging.
 
  continuous (aka linear) mode maps to the CVENAC (constant voltage)
  feature of the twl4030.
 
 Are you sure? Before your patches CVENAC was set at all times and and
 charger still worked in automatic mode.
 
 
  Signed-off-by: NeilBrown ne...@suse.de
  ---
   drivers/power/twl4030_charger.c |   40 
  +--
   1 file changed, 30 insertions(+), 10 deletions(-)
 
  diff --git a/drivers/power/twl4030_charger.c 
  b/drivers/power/twl4030_charger.c
  index 6c53f0b601a4..e5a0225ea87e 100644
  --- a/drivers/power/twl4030_charger.c
  +++ b/drivers/power/twl4030_charger.c
  @@ -112,7 +112,7 @@ struct twl4030_bci {
  int ichg_eoc, ichg_lo, ichg_hi;
  int usb_cur, ac_cur;
  boolac_is_active;
  -   int usb_mode; /* charging mode requested */
  +   int usb_mode, ac_mode; /* charging mode 
  requested */
   #defineCHARGE_OFF  0
   #defineCHARGE_AUTO 1
   #defineCHARGE_LINEAR   2
  @@ -449,12 +449,18 @@ static int twl4030_charger_enable_usb(struct 
  twl4030_bci *bci, bool enable)
   /*
* Enable/Disable AC Charge funtionality.
*/
  -static int twl4030_charger_enable_ac(bool enable)
  +static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable)
   {
  int ret;
 
  -   if (enable)
  -   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
  +   if (bci-ac_mode == CHARGE_OFF)
  +   enable = false;
  +
  +   if (enable  bci-ac_mode == CHARGE_LINEAR)
  +   ret = twl4030_clear_set_boot_bci(0, (TWL4030_CVENAC |
  +TWL4030_BCIAUTOAC));
  +   else if (enable)
  +   ret = twl4030_clear_set_boot_bci(TWL4030_CVENAC, 
  TWL4030_BCIAUTOAC);
  else
  ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC, 0);
 
 CVENAC is required to be set for operation on AC without battery
 (which works fine on most pandora boards). After this patch, when
 booted without battery,  the board will reset before there is a chance
 to set the linear mode by userspace, because this is called on
 probe...
 

Yes, it looks like I misunderstood CVENAC a bit - thanks.

I've removed 'continuous' mode for AC and no longer clear or set that bit.

Thanks,
NeilBrown


pgplztCo9D_mx.pgp
Description: OpenPGP digital signature


[PATCH 13/14] twl4030_charger: Increase current carefully while watching voltage.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

The USB Battery Charging spec (BC1.2) suggests a dedicated
charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25
volts.

To choose the correct current voltage setting requires a trial
and error approach: try to draw current and see if the voltage drops
too low.

Even with a configured Standard Downstream Port, it may not be possible
to reliably pull 500mA - depending on cable quality and source
quality I have reports of charging failure due to the voltage dropping
too low.

To address both these concerns, this patch introduce incremental
current setting.
The current pull from VBUS is increased in steps of 20mA every 100ms
until the target is reached or until the measure voltage drops below
4.75V.  If the voltage does go too low, the target current is reduced
by 20mA and kept there.

This applies to currents selected automatically, or to values
set via sysfs.  So setting a large value will cause the maximum
available to be used - up to the limit of 1.7A imposed by the
hardware.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   68 ++-
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 73c7cd96ebc1..d0199495dddc 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -119,6 +119,18 @@ struct twl4030_bci {
 #defineCHARGE_AUTO 1
 #defineCHARGE_LINEAR   2
 
+   /* When setting the USB current we slowly increase the
+* requested current until target is reached or the voltage
+* drops below 4.75V.  In the latter case we step back one
+* step.
+*/
+   unsigned intusb_cur_target;
+   struct delayed_work current_worker;
+#defineUSB_CUR_STEP2   /* 20mA at a time */
+#defineUSB_MIN_VOLT475 /* 4.75V */
+#defineUSB_CUR_DELAY   msecs_to_jiffies(100)
+#defineUSB_MAX_CURRENT 170 /* TWL4030 caps at 1.7A */
+
unsigned long   event;
 };
 
@@ -257,6 +269,12 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
} else {
cur = bci-usb_cur;
bci-ac_is_active = false;
+   if (cur  bci-usb_cur_target) {
+   cur = bci-usb_cur_target;
+   bci-usb_cur = cur;
+   }
+   if (cur  bci-usb_cur_target)
+   schedule_delayed_work(bci-current_worker, 
USB_CUR_DELAY);
}
 
/* First, check thresholds and see if cgain is needed */
@@ -391,6 +409,38 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
return 0;
 }
 
+static void twl4030_current_worker(struct work_struct *data)
+{
+   int v;
+   int res;
+   struct twl4030_bci *bci = container_of(data, struct twl4030_bci,
+  current_worker.work);
+
+   res = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
+   if (res  0)
+   v = 0;
+   else
+   /* BCIVBUS uses ADCIN8, 7/1023 V/step */
+   v = res * 6843;
+
+   printk(v=%d cur=%d target=%d\n, v, bci-usb_cur,
+  bci-usb_cur_target);
+
+   if (v  USB_MIN_VOLT) {
+   /* Back up and stop adjusting. */
+   bci-usb_cur -= USB_CUR_STEP;
+   bci-usb_cur_target = bci-usb_cur;
+   } else if (bci-usb_cur = bci-usb_cur_target ||
+  bci-usb_cur + USB_CUR_STEP  USB_MAX_CURRENT) {
+   /* Reached target and voltage is OK - stop */
+   return;
+   } else {
+   bci-usb_cur += USB_CUR_STEP;
+   schedule_delayed_work(bci-current_worker, USB_CUR_DELAY);
+   }
+   twl4030_charger_update_current(bci);
+}
+
 /*
  * Enable/Disable USB Charge functionality.
  */
@@ -451,6 +501,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
pm_runtime_put_autosuspend(bci-transceiver-dev);
bci-usb_enabled = 0;
}
+   bci-usb_cur = 0;
}
 
return ret;
@@ -599,7 +650,7 @@ twl4030_bci_max_current_store(struct device *dev, struct 
device_attribute *attr,
if (dev == bci-ac.dev)
bci-ac_cur = cur;
else
-   bci-usb_cur = cur;
+   bci-usb_cur_target = cur;
 
twl4030_charger_update_current(bci);
return n;
@@ -621,7 +672,7 @@ static ssize_t twl4030_bci_max_current_show(struct device 
*dev,
cur = bci-ac_cur;
} else {
if (bci-ac_is_active)
-   cur = bci-usb_cur;
+   cur = bci-usb_cur_target;
}
if (cur  0) {
cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
@@ -664,14 +715,14 @@ static int twl4030_bci_usb_ncb

[PATCH 12/14] twl4030_charger: add ac/mode to match usb/mode

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

This allows AC charging to be turned off, much like usb charging.
continuous mode is not available though.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 .../ABI/testing/sysfs-class-power-twl4030  |   10 ++
 drivers/power/twl4030_charger.c|   35 +++-
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
index c27e8ca8c9db..35a211b9a172 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -33,3 +33,13 @@ Description:
 This is useful for unstable power sources
 such as bicycle dynamo, but care should
 be taken that battery is not over-charged.
+
+What: /sys/class/power_supply/twl4030_ac/mode
+Description:
+   Changing mode for 'ac' port.
+   Writing to this can disable charging.
+
+   Possible values are:
+   auto - draw power as appropriate for detected
+power source and battery status.
+   off  - do not draw any power.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 2c8d85102def..73c7cd96ebc1 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -114,7 +114,7 @@ struct twl4030_bci {
unsigned intichg_eoc, ichg_lo, ichg_hi;
unsigned intusb_cur, ac_cur;
boolac_is_active;
-   int usb_mode; /* charging mode requested */
+   int usb_mode, ac_mode; /* charging mode requested */
 #defineCHARGE_OFF  0
 #defineCHARGE_AUTO 1
 #defineCHARGE_LINEAR   2
@@ -459,10 +459,13 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 /*
  * Enable/Disable AC Charge funtionality.
  */
-static int twl4030_charger_enable_ac(bool enable)
+static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable)
 {
int ret;
 
+   if (bci-ac_mode == CHARGE_OFF)
+   enable = false;
+
if (enable)
ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
else
@@ -693,9 +696,17 @@ twl4030_bci_mode_store(struct device *dev, struct 
device_attribute *attr,
mode = 2;
else
return -EINVAL;
-   twl4030_charger_enable_usb(bci, false);
-   bci-usb_mode = mode;
-   status = twl4030_charger_enable_usb(bci, true);
+   if (dev == bci-ac.dev) {
+   if (mode == 2)
+   return -EINVAL;
+   twl4030_charger_enable_ac(bci, false);
+   bci-ac_mode = mode;
+   status = twl4030_charger_enable_ac(bci, true);
+   } else {
+   twl4030_charger_enable_usb(bci, false);
+   bci-usb_mode = mode;
+   status = twl4030_charger_enable_usb(bci, true);
+   }
return (status == 0) ? n : status;
 }
 
@@ -709,9 +720,13 @@ twl4030_bci_mode_show(struct device *dev,
struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
int len = 0;
int i;
+   int mode = bci-usb_mode;
+
+   if (dev == bci-ac.dev)
+   mode = bci-ac_mode;
 
for (i = 0; i  ARRAY_SIZE(modes); i++)
-   if (bci-usb_mode == i)
+   if (mode == i)
len += snprintf(buf+len, PAGE_SIZE-len,
[%s] , modes[i]);
else
@@ -905,6 +920,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
else
bci-usb_cur = 10;  /* 100mA */
bci-usb_mode = CHARGE_AUTO;
+   bci-ac_mode = CHARGE_AUTO;
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);
@@ -993,10 +1009,12 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-usb.dev, dev_attr_mode))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-ac.dev, dev_attr_mode))
+   dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-ac.dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
 
-   twl4030_charger_enable_ac(true);
+   twl4030_charger_enable_ac(bci, true);
if (!IS_ERR_OR_NULL(bci-transceiver))
twl4030_bci_usb_ncb(bci-usb_nb,
bci-transceiver-last_event,
@@ -1016,13 +1034,14 @@ static int __exit twl4030_bci_remove(struct 
platform_device *pdev)
 {
struct twl4030_bci *bci = platform_get_drvdata(pdev);
 
-   twl4030_charger_enable_ac(false

[PATCH 08/14] twl4030_charger: allow max_current to be managed via sysfs.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

'max_current' sysfs attributes are created which allow the
max to be set.
Whenever a current source changes, the default is restored.
This will be followed by a uevent, so user-space can decide to
update again.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 .../ABI/testing/sysfs-class-power-twl4030  |   15 
 drivers/power/twl4030_charger.c|   72 
 2 files changed, 87 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-power-twl4030

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
new file mode 100644
index ..06092209d851
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -0,0 +1,15 @@
+What: /sys/class/power_supply/twl4030_ac/max_current
+  /sys/class/power_supply/twl4030_usb/max_current
+Description:
+   Read/Write limit on current which which may
+   be drawn from the ac (Accessory Charger) or
+   USB port.
+
+   Value is in micro-Amps.
+
+   Value is set automatically to an appropriate
+   value when a cable is plugged on unplugged.
+
+   Value can the set by writing to the attribute.
+   The change will only persist until the next
+   plug event.  These event are reported via udev.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 37f2f40991ee..df031b0123d0 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -482,6 +482,8 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void 
*arg)
struct twl4030_bci *bci = arg;
 
dev_dbg(bci-dev, CHG_PRES irq\n);
+   /* reset current on each 'plug' event */
+   bci-ac_cur = 50;
twl4030_charger_update_current(bci);
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
@@ -536,6 +538,63 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void 
*arg)
return IRQ_HANDLED;
 }
 
+/*
+ * Provide max_current attribute in sysfs.
+ */
+static ssize_t
+twl4030_bci_max_current_store(struct device *dev, struct device_attribute 
*attr,
+   const char *buf, size_t n)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int cur = 0;
+   int status = 0;
+   status = kstrtoint(buf, 10, cur);
+   if (status)
+   return status;
+   if (cur  0)
+   return -EINVAL;
+   if (dev == bci-ac.dev)
+   bci-ac_cur = cur;
+   else
+   bci-usb_cur = cur;
+
+   twl4030_charger_update_current(bci);
+   return n;
+}
+
+/*
+ * sysfs max_current show
+ */
+static ssize_t twl4030_bci_max_current_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   int status = 0;
+   int cur = -1;
+   u8 bcictl1;
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+
+   if (dev == bci-ac.dev) {
+   if (!bci-ac_is_active)
+   cur = bci-ac_cur;
+   } else {
+   if (bci-ac_is_active)
+   cur = bci-usb_cur;
+   }
+   if (cur  0) {
+   cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
+   if (cur  0)
+   return cur;
+   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
+   if (status  0)
+   return status;
+   cur = regval2ua(cur, bcictl1  TWL4030_CGAIN);
+   }
+   return scnprintf(buf, PAGE_SIZE, %u\n, cur);
+}
+
+static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show,
+   twl4030_bci_max_current_store);
+
 static void twl4030_bci_usb_work(struct work_struct *data)
 {
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
@@ -558,6 +617,12 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
 
dev_dbg(bci-dev, OTG notify %lu\n, val);
 
+   /* reset current on each 'plug' event */
+   if (allow_usb)
+   bci-usb_cur = 50;
+   else
+   bci-usb_cur = 10;
+
bci-event = val;
schedule_work(bci-work);
 
@@ -818,6 +883,11 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
dev_warn(pdev-dev, failed to unmask interrupts: %d\n, ret);
 
twl4030_charger_update_current(bci);
+   if (device_create_file(bci-usb.dev, dev_attr_max_current))
+   dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-ac.dev, dev_attr_max_current))
+   dev_warn(pdev-dev, could not create sysfs file\n);
+
twl4030_charger_enable_ac(true);
if (!IS_ERR_OR_NULL(bci-transceiver))
twl4030_bci_usb_ncb(bci-usb_nb,
@@ -842,6 +912,8 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev

[PATCH 07/14] twl4030_charger: distinguish between USB current and 'AC' current

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

The twl4030 charger has two current sources, 'USB' and 'AC'
(presumably Accessory Charger).

If 'AC' is providing current, we should set the current limit
differently to when it isn't (and so USB is used).
So split 'cur' into 'usb_cur' and 'ac_cur' and use accordingly.

Now we must review the current setting on any interrupt or USB
event which might indicate that the charger-source has changed.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   36 +---
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 02d677ef63e2..37f2f40991ee 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,6 +22,7 @@
 #include linux/power_supply.h
 #include linux/notifier.h
 #include linux/usb/otg.h
+#include linux/i2c/twl4030-madc.h
 
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
@@ -101,10 +102,13 @@ struct twl4030_bci {
int usb_enabled;
 
/*
-* ichg values in uA. If any are 'large', we set CGAIN to
-* '1' which doubles the range for half the precision.
+* ichg_* and *_cur values in uA. If any are 'large', we set
+* CGAIN to '1' which doubles the range for half the
+* precision.
 */
-   unsigned intichg_eoc, ichg_lo, ichg_hi, cur;
+   unsigned intichg_eoc, ichg_lo, ichg_hi;
+   unsigned intusb_cur, ac_cur;
+   boolac_is_active;
 
unsigned long   event;
 };
@@ -225,11 +229,24 @@ static int ua2regval(int ua, bool cgain)
 static int twl4030_charger_update_current(struct twl4030_bci *bci)
 {
int status;
+   int cur;
unsigned reg, cur_reg;
u8 bcictl1, oldreg, fullreg;
bool cgain = false;
u8 boot_bci;
 
+   /*
+* If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
+* and AC is enabled, set current for 'ac'
+*/
+   if (twl4030_get_madc_conversion(11)  4500) {
+   cur = bci-ac_cur;
+   bci-ac_is_active = true;
+   } else {
+   cur = bci-usb_cur;
+   bci-ac_is_active = false;
+   }
+
/* First, check thresholds and see if cgain is needed */
if (bci-ichg_eoc = 20)
cgain = true;
@@ -237,7 +254,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
cgain = true;
if (bci-ichg_hi = 82)
cgain = true;
-   if (bci-cur  852000)
+   if (cur  852000)
cgain = true;
 
status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
@@ -318,7 +335,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
 * And finally, set the current.  This is stored in
 * two registers.
 */
-   reg = ua2regval(bci-cur, cgain);
+   reg = ua2regval(cur, cgain);
/* we have only 10 bits */
if (reg  0x3ff)
reg = 0x3ff;
@@ -371,6 +388,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
 
+   twl4030_charger_update_current(bci);
+
/* Need to keep phy powered */
if (!bci-usb_enabled) {
pm_runtime_get_sync(bci-transceiver-dev);
@@ -463,6 +482,7 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void 
*arg)
struct twl4030_bci *bci = arg;
 
dev_dbg(bci-dev, CHG_PRES irq\n);
+   twl4030_charger_update_current(bci);
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
 
@@ -495,6 +515,7 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
}
+   twl4030_charger_update_current(bci);
 
/* various monitoring events, for now we just log them here */
if (irqs1  (TWL4030_TBATOR2 | TWL4030_TBATOR1))
@@ -708,10 +729,11 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
bci-ichg_eoc = 80100; /* Stop charging when current drops to here */
bci-ichg_lo = 241000; /* Low threshold */
bci-ichg_hi = 50; /* High threshold */
+   bci-ac_cur = 50; /* 500mA */
if (allow_usb)
-   bci-cur = 50;  /* 500mA */
+   bci-usb_cur = 50;  /* 500mA */
else
-   bci-cur = 10;  /* 100mA */
+   bci-usb_cur = 10;  /* 100mA */
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org

[PATCH 10/14] twl4030_charger: enable manual enable/disable of usb charging.

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

'off' or 'auto' to

 /sys/class/power/twl4030_usb/mode

will now enable or disable charging from USB port.  Normally this is
enabled on 'plug' and disabled on 'unplug'.
Unplug will still disable charging.  'plug' will only enable it if
'auto' if selected.

Acked-by: Pavel Machek pa...@ucw.cz
Signed-off-by: NeilBrown ne...@suse.de
---
 .../ABI/testing/sysfs-class-power-twl4030  |   11 
 drivers/power/twl4030_charger.c|   59 
 2 files changed, 70 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 
b/Documentation/ABI/testing/sysfs-class-power-twl4030
index 06092209d851..390db7a55231 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -13,3 +13,14 @@ Description:
Value can the set by writing to the attribute.
The change will only persist until the next
plug event.  These event are reported via udev.
+
+
+What: /sys/class/power_supply/twl4030_usb/mode
+Description:
+   Changing mode for USB port.
+   Writing to this can disable charging.
+
+   Possible values are:
+   auto - draw power as appropriate for detected
+power source and battery status.
+   off  - do not draw any power.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 2042e7619954..802cdd6d3e00 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -109,10 +109,16 @@ struct twl4030_bci {
unsigned intichg_eoc, ichg_lo, ichg_hi;
unsigned intusb_cur, ac_cur;
boolac_is_active;
+   int usb_mode; /* charging mode requested */
+#defineCHARGE_OFF  0
+#defineCHARGE_AUTO 1
 
unsigned long   event;
 };
 
+/* strings for 'usb_mode' values */
+static char *modes[] = { off, auto };
+
 /*
  * clear and set bits on an given register on a given module
  */
@@ -386,6 +392,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 {
int ret;
 
+   if (bci-usb_mode == CHARGE_OFF)
+   enable = false;
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
 
twl4030_charger_update_current(bci);
@@ -634,6 +642,53 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
return NOTIFY_OK;
 }
 
+/*
+ * sysfs charger enabled store
+ */
+static ssize_t
+twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int mode;
+   int status;
+
+   if (sysfs_streq(buf, modes[0]))
+   mode = 0;
+   else if (sysfs_streq(buf, modes[1]))
+   mode = 1;
+   else
+   return -EINVAL;
+   twl4030_charger_enable_usb(bci, false);
+   bci-usb_mode = mode;
+   status = twl4030_charger_enable_usb(bci, true);
+   return (status == 0) ? n : status;
+}
+
+/*
+ * sysfs charger enabled show
+ */
+static ssize_t
+twl4030_bci_mode_show(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int len = 0;
+   int i;
+
+   for (i = 0; i  ARRAY_SIZE(modes); i++)
+   if (bci-usb_mode == i)
+   len += snprintf(buf+len, PAGE_SIZE-len,
+   [%s] , modes[i]);
+   else
+   len += snprintf(buf+len, PAGE_SIZE-len,
+   %s , modes[i]);
+   buf[len-1] = '\n';
+   return len;
+}
+static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show,
+  twl4030_bci_mode_store);
+
 static int twl4030_charger_get_current(void)
 {
int curr;
@@ -804,6 +859,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
bci-usb_cur = 50;  /* 500mA */
else
bci-usb_cur = 10;  /* 100mA */
+   bci-usb_mode = CHARGE_AUTO;
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);
@@ -890,6 +946,8 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
twl4030_charger_update_current(bci);
if (device_create_file(bci-usb.dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-usb.dev, dev_attr_mode))
+   dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-ac.dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
 
@@ -918,6 +976,7 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
twl4030_charger_enable_backup(0, 0

[PATCH 00/14] Enhance twl4030_charger functionality. - V2

2015-03-22 Thread NeilBrown
Hi Sebastian,
 here is V2 of my patches to improve the twl4030 charger.
 They include improved documentation and removal of changes
 to the CVENAC bit which I didn't properly understand.

 One patch needs to make a change in drivers/mfd, and that has
 been acked by Lee Jones.

Summary from before:
These patches make a number of improvements to twl4030_charger.

Some are just internal cleanups (e.g. use of devres).  Others allow
better control of charging through both manual and automatic means.

- the maximum current can be configured via sysfs.
- the charger will only draw that current if it can do so without
  the voltage dropping too much
- a 'continuous' mode is available which ignores voltage and just
  takes what it can (to be used with caution, but very useful in
  some circumstances).
- 'ac' and 'usb' power sources can be configured separately.


Thanks,
NeilBrown

---

NeilBrown (14):
  twl4030_charger: use devm_request_threaded_irq
  twl4030_charger: use devres for power_supply_register and kzalloc.
  twl4030_charger: use runtime_pm to keep usb phy active while charging.
  twl4030_charger: trust phy to determine when USB power is available.
  twl4030_charger: split uA calculation into a function.
  twl4030_charger: allow fine control of charger current.
  twl4030_charger: distinguish between USB current and 'AC' current
  twl4030_charger: allow max_current to be managed via sysfs.
  twl4030_charger: only draw USB current as negotiated with host.
  twl4030_charger: enable manual enable/disable of usb charging.
  twl4030_charger: add software controlled linear charging mode.
  twl4030_charger: add ac/mode to match usb/mode
  twl4030_charger: Increase current carefully while watching voltage.
  twl4030_charger: assume a 'charger' can supply maximum current.


 .../ABI/testing/sysfs-class-power-twl4030  |   45 ++
 drivers/mfd/twl-core.c |9 
 drivers/power/twl4030_charger.c|  573 +---
 3 files changed, 536 insertions(+), 91 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-power-twl4030

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/14] twl4030_charger: use devm_request_threaded_irq

2015-03-22 Thread NeilBrown
From: NeilBrown ne...@suse.de

This simplifies the error paths.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index b07f4e2f2dde..58996d252ecf 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -610,21 +610,21 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
goto fail_register_usb;
}
 
-   ret = request_threaded_irq(bci-irq_chg, NULL,
+   ret = devm_request_threaded_irq(pdev-dev, bci-irq_chg, NULL,
twl4030_charger_interrupt, IRQF_ONESHOT, pdev-name,
bci);
if (ret  0) {
dev_err(pdev-dev, could not request irq %d, status %d\n,
bci-irq_chg, ret);
-   goto fail_chg_irq;
+   goto fail;
}
 
-   ret = request_threaded_irq(bci-irq_bci, NULL,
+   ret = devm_request_threaded_irq(pdev-dev, bci-irq_bci, NULL,
twl4030_bci_interrupt, IRQF_ONESHOT, pdev-name, bci);
if (ret  0) {
dev_err(pdev-dev, could not request irq %d, status %d\n,
bci-irq_bci, ret);
-   goto fail_bci_irq;
+   goto fail;
}
 
INIT_WORK(bci-work, twl4030_bci_usb_work);
@@ -647,7 +647,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
   TWL4030_INTERRUPTS_BCIIMR1A);
if (ret  0) {
dev_err(pdev-dev, failed to unmask interrupts: %d\n, ret);
-   goto fail_unmask_interrupts;
+   goto fail;
}
 
reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
@@ -666,11 +666,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
 
return 0;
 
-fail_unmask_interrupts:
-   free_irq(bci-irq_bci, bci);
-fail_bci_irq:
-   free_irq(bci-irq_chg, bci);
-fail_chg_irq:
+fail:
power_supply_unregister(bci-usb);
 fail_register_usb:
power_supply_unregister(bci-ac);
@@ -695,8 +691,6 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR2A);
 
-   free_irq(bci-irq_bci, bci);
-   free_irq(bci-irq_chg, bci);
power_supply_unregister(bci-usb);
power_supply_unregister(bci-ac);
kfree(bci);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: twl4030_charger: need changes to get probed?

2015-03-08 Thread NeilBrown
On Sat, 7 Mar 2015 22:01:02 +0100 Sebastian Reichel s...@debian.org wrote:

 Hi,
 
 On Fri, Mar 06, 2015 at 10:24:17PM +0100, Pavel Machek wrote:
  According to n900 dts, twl4030-bci (aka charger) should be
  included.
 
 its part of twl, but not used on N900 afaik.
 
  (But it does not seem to do anything useful on n900. I was hoping for
  measurement of input voltage, but .. no.)
 
 check for rx51-battery.
 
  Any ideas why the patch below is needed?
 
 platform_driver_probe() does not support deferred probing.
 
 Neil, can you take this patch into your series for the next round?

I could, but I do wonder if it is the right thing to do.

Shouldn't we fix platform_driver_probe() to support deferred probing.

As I understand it, it refused to retry a probe if there is an error, and the
comments suggest that such retrying is avoided because it would be a waste
of time:

/*
 * Prevent driver from requesting probe deferral to avoid further
 * futile probe attempts.
 */

In this case, it isn't futile.

Earlier there is a comment saying:

 * Use this instead of platform_driver_register() when you know the device
 * is not hotpluggable and has already been registered, and you want to
 * remove its run-once probe() infrastructure from memory after the driver
 * has bound to the device.

I presume all this applies.  I assume that the only problem is a probe-order
thing.  So maybe we should fix platform_driver_probe() to do the right thing
with -EPROBEDEFER??

Trouble is, I really don't understand the  point or mechanism for
platform_driver_probe(), so I cannot suggest anything.
But I have been annoyed before that platform_driver_probe doesn't cope with
EPROBEDEFER, so I would like it fixed.

NeilBrown


pgp5MxAjPABro.pgp
Description: OpenPGP digital signature


Re: [PATCH 15/15] twl4030_charger: assume a 'charger' can supply maximum current.

2015-03-04 Thread NeilBrown
On Mon, 2 Mar 2015 22:29:39 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 15:33:53, NeilBrown wrote:
  If it cannot, we will stop pulling more current when voltage drops.
 
 Can you justify it a bit more?
 
 I mean... maybe there's a fuse in the charger? Or maybe it will supply
 the current but overheat in the process? (USB_MAX_CURRENT is 500mA or
 1.7A?)

USB_MAX_CURRENT is 1.7A - the most the twl4030 will manage.

The relevant specs say that a charger can deliver from 0.5A to 5.0A at between
4.75 and 5.25 volts.
They don't, as far as I can tell, describe how a gadget can determine where
in those ranges the charger is actually happy.

My understanding of electronics suggests that if you start to pull too much
current, the voltage will start to drop.  It is that voltage drop across
internal resistance which causes over-heating.

So if voltage is above 4.75 volts, it seems reasonable to assume that the
charger is happy.

The code currently (see previous patch) ramps up the current until the
voltage drops below 4.75, or until the maximum is reached.
If the voltage drops, it backs off.
The current should  only be too high for 100ms.  Hopefully not too long.

I'm very open if anyone can suggest a more safe way to make full use of a
charger without risking excess current draw, but I cannot find one.

Maybe I should measure the unloaded voltage, and not let it drop more than
0.25V below that?

I'm also very open to someone finding out how to get the twl4030 to detect a
D+ and D- shorted charger.  I think it is supposed to be able to do this,
but I haven't managed to make it work yet.

Thanks,
NeilBrown



pgpVJ8GmrAVeE.pgp
Description: OpenPGP digital signature


Re: [PATCH 12/15] twl4030_charger: add software controlled linear charging mode.

2015-03-04 Thread NeilBrown
On Mon, 2 Mar 2015 22:09:26 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 15:33:52, NeilBrown wrote:
  Add a 'continuous' option for usb charging which enabled
  the linear charging mode of the twl4030.
 
 Documentation/ :-).

!

 
  Linear charging does a good job with not so reliable power sources, since
  several voltage controlling is then often too intelligent.
 
 Parse error.


Linear charging does a good job with not-so-reliable power sources.
Auto mode does not work well as it switches off when voltage drops
momentarily.  Care must be taken not to over-charge.

It was used with a bike hub dynamo since a year or so. In that case
there are automatically charging stops when the cyclist needs a break.
=

 
  It was used with a bike hub dynamo since a year or so. In that case there
  are automatically charging stops when the cyclist needs a break.
  
  Orignal-by: Andreas Kemnade andr...@kemnade.info
  Signed-off-by: NeilBrown ne...@suse.de
 
 
  +   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
  +  TWL4030_BCIWDKEY);
  +   /* 0x24 + EKEY6:  off mode */
 
-  
 
  +   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
  +  TWL4030_BCIMDKEY);
  +   /* EKEY2: Linear charge: usb path */
 
 USB
 
  +   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
  +  TWL4030_BCIMDKEY);
  +   /* WDKEY5: stop watchdog count */
  +   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
  +  TWL4030_BCIWDKEY);
  +   /* enable MFEN3 access */
  +   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c,
  +  TWL4030_BCIMFKEY);
  +/* ICHGEOCEN - end-of-charge monitor (current  80mA)
  + *  (charging continues)
  + * ICHGLOWEN - current level monitor (charge continues)
  + * don't monitor over-current or heat save
 
 Heat save? Is ignoring over-current good idea?

The data sheet refers to a flag HSEN which is Heat Save function enable.

your guess is as good as mine.

We don't currently have any code for responding to warnings.  Maybe we should.

For now this feature is use at your own risk - and one person has found it
very useful.

 
  @@ -650,6 +684,8 @@ twl4030_bci_mode_store(struct device *dev, struct 
  device_attribute *attr,
  mode = 0;
  else if (sysfs_streq(buf, modes[1]))
  mode = 1;
  +   else if (sysfs_streq(buf, modes[2]))
  +   mode = 2;
 
 Time for loop?

When we get one more mode it will be :-)

Thanks,
NeilBrown



pgpSRiRJsR3zi.pgp
Description: OpenPGP digital signature


Re: [PATCH 04/15] twl4030_charger: use runtime_pm to keep usb phy active while charging.

2015-03-04 Thread NeilBrown
On Wed, 25 Feb 2015 07:24:43 + Lee Jones lee.jo...@linaro.org wrote:

 On Tue, 24 Feb 2015, NeilBrown wrote:
 
  The twl4030 usb phy needs to be active while we are using
  the USB VBUS as a current source for charging.
  In particular, the usb3v1 regulator must be enabled and the
  PHY_PWR_PHYPWD bit must be set to keep the phy powered.
  
  commit ab37813f4093a5f59cb8e083cde277289dc72ed3
  twl4030_charger: Allow charger to control the regulator that feeds it
  
  Gave the charger control over the regulator, but didn't resolve
  the PHY_PWR_PHYPWD issue.
  
  Now that both of these are controlled by runtime_pm in
  phy-twl4030-usb, we can simply take a runtime_pm reference to the USB
  phy whenever the charger wants to use it as a current source.
  
  So this patch reverts the above commit, and adds the necessary
  runtime_pm calls.
  
  Signed-off-by: NeilBrown ne...@suse.de
  ---
   drivers/mfd/twl-core.c  |9 -
 
 Acked-by: Lee Jones lee.jo...@linaro.org

Thanks.
I guess that clear it to go in though the 'power supply' tree.

NeilBrown


pgpPxECaAk_kV.pgp
Description: OpenPGP digital signature


Re: [PATCH 09/15] twl4030_charger: allow max_current to be managed via sysfs.

2015-03-04 Thread NeilBrown
On Mon, 2 Mar 2015 22:05:26 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 15:33:52, NeilBrown wrote:
  'max_current' sysfs attributes are created which allow the
  max to be set.
  Whenever a current source changes, the default is restored.
  This will be followed by a uevent, so user-space can decide to
  update again.
 
 Does this need Documentation update?

Oh all right... I've created the relevant documentation in Documentation/ABI.

It seems persistence pays off :-)


 
  Signed-off-by: NeilBrown ne...@suse.de
  ---
   drivers/power/twl4030_charger.c |   76 
  +++
   1 file changed, 76 insertions(+)
  
  diff --git a/drivers/power/twl4030_charger.c 
  b/drivers/power/twl4030_charger.c
  index bfc9b808301e..b0242786d047 100644
  --- a/drivers/power/twl4030_charger.c
  +++ b/drivers/power/twl4030_charger.c
  @@ -527,6 +529,67 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void 
  *arg)
  return IRQ_HANDLED;
   }
   
  +/*
  + * sysfs max_current store
  + */
 
 That's not exactly useful comment.

Now:

 * Provide max_current attribute in sysfs.

 
  +static ssize_t
  +twl4030_bci_max_current_store(struct device *dev, struct device_attribute 
  *attr,
  +   const char *buf, size_t n)
  +{
  +   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
  +   int cur = 0;
  +   int status = 0;
  +   status = kstrtoint(buf, 10, cur);
  +   if (status)
  +   return status;
  +   if (cur  0)
  +   return -EINVAL;
  +   if (dev == bci-ac.dev) {
  +   if (bci-ac_cur == cur)
  +   return n;
  +   bci-ac_cur = cur;
  +   } else {
  +   if (bci-usb_cur == cur)
  +   return n;
  +   bci-usb_cur = cur;
  +   }
  +   twl4030_charger_update_current(bci);
  +   return (status == 0) ? n : status;
  +}
 
 Uff. but we know that status == 0 at this point, no? 

Yes.  Fixed.

   Also... is
 optimalization of not calling update_current() when nothing changed
 worth it?

Probably not... and  code looks a lot nicer if I remove that.
So I have.


 
  +/*
  + * sysfs max_current show
  + */
  +static ssize_t twl4030_bci_max_current_show(struct device *dev,
  +   struct device_attribute *attr, char *buf)
  +{
  +   int status = 0;
  +   int cur = -1;
  +   u8 bcictl1;
  +   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
  +
  +   if (dev == bci-ac.dev) {
  +   if (!bci-ac_is_active)
  +   cur = bci-ac_cur;
  +   } else {
  +   if (bci-ac_is_active)
  +   cur = bci-usb_cur;
  +   }
  +   if (cur  0) {
  +   cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
  +   if (cur  0)
  +   return cur;
  +   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
  +   if (status  0)
  +   return status;
  +   cur = regval2ua(cur, bcictl1  TWL4030_CGAIN);
  +   }
  +   return scnprintf(buf, PAGE_SIZE, %u\n, cur);
  +}
 
 Is this in uA or mA? uA. Ok.

uA, now described in Documentation/ABI/testing/sysfs-class-power-twl4030

+What: /sys/class/power_supply/twl4030_ac/max_current
+  /sys/class/power_supply/twl4030_usb/max_current
+Description:
+   Read/Write limit on current which which may
+   be drawn from the ac (Accessory Charger) or
+   USB port.
+
+   Value is in micro-Amps.
+
+   Value is set automatically to an appropriate
+   value when a cable is plugged on unplugged.
+
+   Value can the set by writing to the attribute.
+   The change will only persist until the next
+   plug event.  These event are reported via udev.


 
 Acked-by: Pavel Machek pa...@ucw.cz
   Pavel
 

Thanks,
NeilBrown


pgpUEAx3Scuug.pgp
Description: OpenPGP digital signature


Re: [PATCH 14/15] twl4030_charger: Increase current carefully while watching voltage.

2015-03-04 Thread NeilBrown
On Mon, 2 Mar 2015 22:29:45 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 15:33:53, NeilBrown wrote:
  The USB Battery Charging spec (BC1.2) suggests a dedicated
  charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25
  volts.
  
  To choose the correct current voltage setting requires a trial
  and error approach: try to draw current and see if the voltage drops
  too low.
  
  Even with a configure Standard Downstream Port, it may not be possible
  to reliably pull 500mA - depending on cable quality and source
 
 configured?
 
  quality I have reports of charging failure due to the voltage dropping
  too low.
  
  To address both these concern, this patch introduce incremental
 
 concerns.
 
  current setting.
  The current pull from VBUS is increased in steps of 20mA every 100ms
  until the target is reached or until the measure voltage drops below
  4.75V.  If the voltage does go too long, the target current is reduced
 
 too low?
 
  by 20mA and kept there.
  
  This applies to currents selected automatically, or to values
  set via sysfs.  So setting a large value will cause the maximum
  available to be used - up to the limit of 1.7mA imposed by the
  hardware.
 
 1.7A?
 
 
  @@ -249,8 +261,14 @@ static int twl4030_charger_update_current(struct 
  twl4030_bci *bci)
  cur = bci-ac_cur;
  bci-ac_is_active = 1;
  } else {
  -   cur = bci-usb_cur;
  +   cur = bci-usb_cur_actual;
 
 usb_cur_actual is not a really great variable name...

I changed usb_cur to usb_cur_target and
usb_cur_actual to usb_cur.

 
  bci-ac_is_active = 0;
  +   if (cur  bci-usb_cur) {
  +   cur = bci-usb_cur;
  +   bci-usb_cur_actual = cur;
  +   }
  +   if (cur  bci-usb_cur)
  +   schedule_delayed_work(bci-current_worker, 
  USB_CUR_DELAY);
  }
   
  /* First, check thresholds and see if cgain is needed */
  @@ -379,6 +397,38 @@ static int twl4030_charger_update_current(struct 
  twl4030_bci *bci)
  return 0;
   }
   
  +static void twl4030_current_worker(struct work_struct *data)
  +{
  +   int v;
  +   int res;
  +   struct twl4030_bci *bci = container_of(data, struct twl4030_bci,
  +  current_worker.work);
  +
  +   res = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
  +   if (res  0)
  +   v = 0;
  +   else
  +   /* BCIVBUS uses ADCIN8, 7/1023 V/step */
  +   v = res * 6843;
  +
  +   printk(v=%d cur=%d target=%d\n, v, bci-usb_cur_actual,
  +  bci-usb_cur);
  +
  +   if (v  USB_MIN_VOLT) {
  +   /* Back up and stop adjusting. */
  +   bci-usb_cur_actual -= USB_CUR_STEP;
  +   bci-usb_cur = bci-usb_cur_actual;
  +   } else if (bci-usb_cur_actual = bci-usb_cur ||
  +  bci-usb_cur_actual + USB_CUR_STEP  USB_MAX_CURRENT) {
  +   /* Reach target and volts are OK - stop */
 
 Reached ... and the voltage is OK - stop.
 
 

Thanks for all your proof-reading :-)

NeilBrown


pgpJjaK_GqbTb.pgp
Description: OpenPGP digital signature


Re: [PATCH 06/15] twl4030_charger: split uA calculation into a function.

2015-03-04 Thread NeilBrown
On Mon, 2 Mar 2015 22:05:18 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 15:33:51, NeilBrown wrote:
  We will need this calculation in other places, so
  create functions to map between register value and uA value.
  
  Signed-off-by: NeilBrown ne...@suse.de
 
 Acked-by: Pavel Machek pa...@ucw.cz

Thanks.


 
  +static int regval2ua(int regval, bool cgain)
  +{
  +   if (cgain)
  +   return (regval * 16618 - 8500 * 1000) / 5;
  +   else
  +   return (regval * 16618 - 8500 * 1000) / 10;
  +}
 
int res = (regval * 16618 - 8500 * 1000);
if (cgain)
   return res / 5;
return res / 10;
 
 ?
   Pavel

Maybe ... not sure it is really more readable.  I think I'll leave it as is.

Thanks,
NeilBrown


pgpGQcRlihT4k.pgp
Description: OpenPGP digital signature


Re: [PATCH 1/4] usb: phy: twl4030: make runtime pm more reliable.

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:03:59 +0100 Pavel Machek pa...@ucw.cz wrote:

 Hi!
 
  +   status_changed =
  +   (twl-linkstat == OMAP_MUSB_VBUS_VALID ||
  +twl-linkstat == OMAP_MUSB_ID_GROUND)
  +   !=
  +   (status == OMAP_MUSB_VBUS_VALID ||
  +status == OMAP_MUSB_ID_GROUND);
  twl-linkstat = status;
 ...
  @@ -768,6 +770,10 @@ static int twl4030_usb_remove(struct platform_device 
  *pdev)
   
  /* disable complete OTG block */
  twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
  +
  +   if (twl-linkstat == OMAP_MUSB_VBUS_VALID ||
  +   twl-linkstat == OMAP_MUSB_ID_GROUND)
  +   pm_runtime_put_noidle(twl-dev);
  pm_runtime_mark_last_busy(twl-dev);
 
 inline function returning (x == OMAP_MUSB_VBUS_VALID || x ==
 OMAP_MUSB_ID_GROUND) would really help readability here.
 
 Thanks,
   Pavel

Good idea.  I've done that.  The function is called cable_present().

Thanks,
NeilBrown


pgpbO85e0cIau.pgp
Description: OpenPGP digital signature


Re: [PATCH 08/15] twl4030_charger: distinguish between USB current and 'AC' current

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:05:10 +0100 Pavel Machek pa...@ucw.cz wrote:

 Hi!
 
  The twl4030 charger has two current sources, 'USB' and 'AC' (which is
  really DC of course...).
  
  If 'AC' is providing current, we should set the current limit
  differently to when it isn't (and so USB is used).
  So split 'cur' into 'usb_cur' and 'ac_cur' and use accordingly.
  
  Now we must review the current setting on any interrupt or USB
  event which might indicate that the charger-source has changed.
  
  Signed-off-by: NeilBrown ne...@suse.de
 
  @@ -103,7 +104,9 @@ struct twl4030_bci {
  /* ichg values in uA. If any are 'large', we set CGAIN to
 
 ichg/_cur values
 
   * '1' which doubles the range for half the precision.
   */
  -   int ichg_eoc, ichg_lo, ichg_hi, cur;
  +   int ichg_eoc, ichg_lo, ichg_hi;
  +   int usb_cur, ac_cur;
 
  +   /* If VAC exceeds 4.5V (MADC 11) and ac is enabled, set current
  +* for 'ac'
 
   /*
* If AC voltage exceeds 4.5V (MADC 11) and AC is enabled, set current
* for 'ac'.
 
 
 Acked-by: Pavel Machek pa...@ucw.cz
 

Thanks - I made those changes, or something much like them.

NeilBrown


pgpIpeDsG7pEg.pgp
Description: OpenPGP digital signature


Re: [PATCH 2/4] usb: phy: twl4030: allow charger to see usb current draw limits.

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:03:55 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 14:40:37, NeilBrown wrote:
  The charger needs to know when a USB gadget has been enumerated
  and what the agreed maximum current was so that it can adjust
  charging accordingly.
  
  So define a set_power() function to record the permitted
  draw, and pass a pointer to that when sending USB_EVENT_ENUMERATED
  notification.
  
  Signed-off-by: NeilBrown ne...@suse.de
  ---
   drivers/phy/phy-twl4030-usb.c |   27 +--
   1 file changed, 21 insertions(+), 6 deletions(-)
  
  diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
  index 97c59074233f..023fe150c7a1 100644
  --- a/drivers/phy/phy-twl4030-usb.c
  +++ b/drivers/phy/phy-twl4030-usb.c
  @@ -163,6 +163,11 @@ struct twl4030_usb {
  enum omap_musb_vbus_id_status linkstat;
  boolvbus_supplied;
   
  +   /* Permitted vbus draw - only meaningful after
 
 add in mA?
 
  +* USB_EVENT_ENUMERATED
  +*/
  +   unsignedvbus_draw;
  +
  struct delayed_work id_workaround_work;
 

Yes.  I make it 'unsigned int' too.

Thanks,
NeilBrown


pgpnzygiI3oWb.pgp
Description: OpenPGP digital signature


Re: [PATCH 07/15] twl4030_charger: allow fine control of charger current.

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:05:01 +0100 Pavel Machek pa...@ucw.cz wrote:

 Hi!
 
  +   /* ichg values in uA. If any are 'large', we set CGAIN to
  +* '1' which doubles the range for half the precision.
  +*/
  +   int ichg_eoc, ichg_lo, ichg_hi, cur;
 
 We should really get uA_t.

Maybe. 32bits allows for  4000A, which should be plenty...
I made it unsigned int.

 
 [Plus, this is not kernel comment style, but...]

Fixed

 
  +   /* For ichg_eoc, reg value must be 100000, we only
  +* set the  in high nibble.
  +*/
 
 Confused. High nibble is 0xf0, right?

does this help?

/*
 * For ichg_eoc, the hardware only supports reg values matching
 * 100000, and requires the  be stored in the high nibble
 * of TWL4030_BCIMFTH8
 */


 
  +   /* And finally, set the current.  This is stored in
  +* two registers. */
  +   reg = ua2regval(bci-cur, cgain);
  +   /* we have only 10 bit */
 
 bits
 
  @@ -562,6 +698,14 @@ static int __init twl4030_bci_probe(struct 
  platform_device *pdev)
  if (!pdata)
  pdata = twl4030_bci_parse_dt(pdev-dev);
   
  +   bci-ichg_eoc = 80100; /* Stop charging when current drops to here */
  +   bci-ichg_lo = 241000; /* low threshold */
 
 Low
 
  +   bci-ichg_hi = 50; /* High threshold */
 
 Acked-by: Pavel Machek pa...@ucw.cz
 

Thanks again!

NeilBrown


pgp0d5hnlrrkh.pgp
Description: OpenPGP digital signature


Re: [PATCH 4/4] usb: phy: twl4030: test ID resistance to see if charger is present.

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:04:44 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 14:40:37, NeilBrown wrote:
  If an 'A' plug is inserted, ID should be pulled to ground.
  If a 'B' plug, then ID should be floating.
  
  If an Accessory Charger Adapter is inserted, then ID will
  be neither grounded nor floating.  In this case tell the
  USB subsystem that it is an A plug, and the battery
  charging subsystem that it is a charger.
 
  Fortunately, this will treat the Openmoko charger (and
  other similar chargers) as a charger.
  
  Signed-off-by: NeilBrown ne...@suse.de
 
 I guess signed-off-by should be real name, so I'd add a space..

This is how I always sign-off my name (2858 times in git log) so I don't
think I'll change it now.

 
 Acked-by: Pavel Machek pa...@ucw.cz

Thanks.

 
  --- a/drivers/phy/phy-twl4030-usb.c
  +++ b/drivers/phy/phy-twl4030-usb.c
  @@ -596,9 +596,31 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
  struct twl4030_usb *twl = _twl;
  enum omap_musb_vbus_id_status status;
  bool status_changed = false;
  +   bool found_charger = false;
   
  status = twl4030_usb_linkstat(twl);
   
  +   if (status == OMAP_MUSB_ID_GROUND ||
  +   status == OMAP_MUSB_VBUS_VALID) {
  +   /* We should check the resistance on the ID pin.
  +* If not a Ground or Floating, then this is
  +* likely a charger
 
 charger., and I guess kernel comments should have /* on separate line.

Yep.

 
 So it will draw .5A from the charger? 1A? 2A?
 
   Pavel

That is up to the charger driver.  The phy just detects what is there, it
doesn't decide what to do with it.

Thanks,
NeilBrown


pgpJgxw0afmzg.pgp
Description: OpenPGP digital signature


Re: [PATCH 11/15] twl4030_charger: enable manual enable/disable of usb charging.

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:03:42 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Tue 2015-02-24 15:33:52, NeilBrown wrote:
  'off' or 'auto' to
  
   /sys/class/power/twl4030_usb/mode
  
  will now enable or disable charging from USB port.  Normally this is
  enabled on 'plug' and disabled on 'unplug'.
  Unplug will still disable charging.  'plug' will only enable it if
  'auto' if selected.
 
 This should go to Documentation/

You mean in Documentation/ABI/stable I guess??

That strikes me as a failed experiment - there is hardly anything there.

I'd be very happy to put the documentation with the code if there was some
mechanism to automatically extract it.  But I really see little value in
Documentation/ABI.

Or did you mean somewhere else?


 
  Signed-off-by: NeilBrown ne...@suse.de
  
  Conflicts:
  drivers/power/twl4030_charger.c
 
 Is it supposed to be here?

ah, no.  Gone now.  Thanks.


 
  diff --git a/drivers/power/twl4030_charger.c 
  b/drivers/power/twl4030_charger.c
  index 01090a440583..19e8dbb1303e 100644
  --- a/drivers/power/twl4030_charger.c
  +++ b/drivers/power/twl4030_charger.c
  @@ -107,6 +107,9 @@ struct twl4030_bci {
  int ichg_eoc, ichg_lo, ichg_hi;
  int usb_cur, ac_cur;
  boolac_is_active;
  +   int usb_mode; /* charging mode requested */
  +#defineCHARGE_OFF  0
  +#defineCHARGE_AUTO 1
   
  unsigned long   event;
   };
  @@ -377,6 +380,8 @@ static int twl4030_charger_enable_usb(struct 
  twl4030_bci *bci, bool enable)
   {
  int ret;
   
 n +  if (bci-usb_mode == CHARGE_OFF)
  +   enable = false;
 
 Sometimes, you use = false and sometimes = 0 when assigning to bools...

I found a fixed a few - thanks.


 
  @@ -629,6 +634,54 @@ static int twl4030_bci_usb_ncb(struct notifier_block 
  *nb, unsigned long val,
  return NOTIFY_OK;
   }
   
  +/*
  + * sysfs charger enabled store
  + */
  +static char *modes[] = { off, auto };
 
 I'd move this before the comment. Or better near struct twl4030_bci.

Makes sense.  Done.  Thanks.


 
  +static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show,
  +  twl4030_bci_mode_store);
  +
   static int twl4030_charger_get_current(void)
   {
  int curr;
  @@ -799,6 +852,7 @@ static int __init twl4030_bci_probe(struct 
  platform_device *pdev)
  bci-usb_cur = 50;  /* 500mA */
  else
  bci-usb_cur = 10;  /* 100mA */
  +   bci-usb_mode = CHARGE_AUTO;
   
  bci-dev = pdev-dev;
  bci-irq_chg = platform_get_irq(pdev, 0);
  @@ -885,6 +939,8 @@ static int __init twl4030_bci_probe(struct 
  platform_device *pdev)
  twl4030_charger_update_current(bci);
  if (device_create_file(bci-usb.dev, dev_attr_max_current))
  dev_warn(pdev-dev, could not create sysfs file\n);
  +   if (device_create_file(bci-usb.dev, dev_attr_mode))
  +   dev_warn(pdev-dev, could not create sysfs file\n);
  if (device_create_file(bci-ac.dev, dev_attr_max_current))
  dev_warn(pdev-dev, could not create sysfs file\n);
   
  @@ -917,6 +973,7 @@ static int __exit twl4030_bci_remove(struct 
  platform_device *pdev)
   
  device_remove_file(bci-usb.dev, dev_attr_max_current);
  device_remove_file(bci-ac.dev, dev_attr_max_current);
  +   device_remove_file(bci-usb.dev, dev_attr_mode);
 
 move the line above for consistency with create?

Yep.

 
 Acked-by: Pavel Machek pa...@ucw.cz

Thanks a lot!

NeilBrown


pgpcgY61j9ce8.pgp
Description: OpenPGP digital signature


Re: [PATCH 3/4] usb: phy: twl4030: add support for reading restore on ID pin.

2015-03-03 Thread NeilBrown
On Mon, 2 Mar 2015 22:04:31 +0100 Pavel Machek pa...@ucw.cz wrote:

 Hi!
 
  The twl4030 phy can measure, with low precision, the
  resistance-to-ground of the ID pin.
  
  Add a function to read the value, and export the result
  via sysfs.
  
  If the read fails, which it does sometimes, try again in 50msec.
  
  Signed-off-by: NeilBrown ne...@suse.de
  ---
   drivers/phy/phy-twl4030-usb.c |   63 
  +
   1 file changed, 63 insertions(+)
  
  diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
  index 023fe150c7a1..759950898df9 100644
  --- a/drivers/phy/phy-twl4030-usb.c
  +++ b/drivers/phy/phy-twl4030-usb.c
  @@ -374,6 +374,56 @@ static void twl4030_i2c_access(struct twl4030_usb 
  *twl, int on)
  }
   }
   
  +enum twl4030_id_status {
  +   TWL4030_GROUND,
  +   TWL4030_102K,
  +   TWL4030_200K,
  +   TWL4030_440K,
  +   TWL4030_FLOATING,
  +   TWL4030_ID_UNKNOWN,
  +};
  +static char *twl4030_id_names[] = {
  +   ground,
  +   102k,
  +   200k,
  +   440k,
 
 New /sys files should be documented somewhere...?

Preferably with the code...

 
 Does it make sense to change 440k - 440KOhm?

Interesting question.  I prefer to avoid including units in files - bare
numbers is better.  But there is no number to match floating unless I spell
it out as infinity, and wouldn't be helpful.

Certainly K would be preferred over k, and given that I have ground
and  floating, it is more consistent to include the Ohm

These are really names, not measures of resistance.  The data sheet calls
them:
 ID_RES_FLOAT  (or sometimes ID_FLOAT)
 ID_RES_440K
 ID_RES_200K
 ID_RES_102K
 ID_GND(or sometimes ID_RES_GND)

So using those names is defensible.

I think I'll change them all to upper case, but leave out the Ohm.
My justification is consistency with the data sheet.




 
 Plus I guess you need to update Documentation/

I guess I'll need to give in to this eventually :-)

 
 Acked-by: Pavel Machek pa...@ucw.cz
 

Thanks,
NeilBrown


pgpAdjFjGRGQh.pgp
Description: OpenPGP digital signature


Re: [PATCH 3/4] mmc: sdio: support switching to 1-bit before turning off clocks

2015-03-03 Thread NeilBrown
On Tue, 3 Mar 2015 14:53:55 -0800 Tony Lindgren t...@atomide.com wrote:

 * NeilBrown ne...@suse.de [150223 18:47]:
  According to section 7.1.2 of
  
  http://www.sandisk.com/media/File/OEM/Manuals/SD_SDIO_specsv1.pdf
  
  In the case where the interrupt mechanism is used to wake the host while
  the card is in a low power state (i.e. no clocks), Both the card and the
  host shall be placed into the 1-bit SD mode prior to stopping the clock.
  
  This is particularly important for the Marvell libertas wifi chip
  in the GTA04.  While in 4-bit mode it will only signal an interrupt
  when the clock is running (which is why setting CLKEXTFREE is
  important).
  In 1-bit mode, the interrupt is asynchronous (explained in OMAP3
  TRM description of the CIRQ flag to MMCHS_STAT:
  
In 1-bit mode, interrupt source is asynchronous (can be a source of
asynchronous wakeup).
In 4-bit mode, interrupt source is sampled during the interrupt
cycle.
  
  )
  
  It is awkward to simply set 1-bit mode in -runtime_suspend
  as that will call mmc_set_ios which calls ops-set_ios(),
  which will likely call pm_runtime_get_sync(), on the device that
  is currently suspending.  This deadlocks.
  
  So:
   - create a work_struct to schedule setting of 1-bit mode
   - introduce an 'sdio_narrowed' state flag which transitions:
   0 (normal) - 1 (convert to 1-bit pending) -
   2 (have switch to 1-bit mode) - 0 (normal)
   - create a function mmc_sdio_want_no_clocks() which can be called
 when the driver wants to turn off clocks (presumably after an
 idle timeout).  This either succeeds (in 1-bit mode) or fails
 and schedules the work to switch to 1-bit mode.
   - when the host is claimed, if sdio_narrowed is 2, restore the
 4-bit bus
   - When the host is released, if sdio_narrowed is 1, then some
 caller other  than our worker claimed the host first, so
 clear sdio_narrowed.
  
  This all allows a graceful and race-free switch to 1-bit mode
  before switching off the clocks, if SDIO interrupts are enabled.
  
  A host should call mmc_sdio_want_no_clocks() when about to turn off
  clocks if sdio interrupts are enabled, and the -disable() function
  should not use a timeout (pm_runtime_put_autosuspend) if
  -sdio_narrowed is 2.
 
 Wow! A mystery finally solved for why libertas_sdio using devices
 like overo won't work for the wakeirqs.. The interface has to be
 in 1-bit mode for libertas to produce any SDIO interrupts..
 
 Below is a patch enabling some more SDIO wakeirqs. Seems to work
 on overo now too :) So tor the whole series, please feel free to
 add:
 
 Tested-by: Tony Lindgren t...@atomide.com

Thanks a lot!


 
 8 ---
 From: Tony Lindgren t...@atomide.com
 Date: Thu, 26 Feb 2015 16:16:03 -0800
 Subject: [PATCH] ARM: dts: Fix omap3 SDIO wakeirqs for devices using 
 sdio_libertas
 
 Turns out the the MMC interface needs to be in 1-bit mode for the
 libertas card to send any SDIO interrupts as pointed out by
 NeilBrown ne...@suse.de. Now that the MMC framework is getting
 fixed for setting 1-bit mode for idle, we can enable SDIO wakeirqs
 for libertas using devices too.
 
 Cc: Andreas Fenkart afenk...@gmail.com
 Cc: Ash Charles a...@gumstix.com
 Cc: Florian Vaussard florian.vauss...@epfl.ch
 Cc: NeilBrown n...@brown.name
 Signed-off-by: Tony Lindgren t...@atomide.com
 
 --- a/arch/arm/boot/dts/omap3-gta04.dtsi
 +++ b/arch/arm/boot/dts/omap3-gta04.dtsi
 @@ -367,6 +367,7 @@
  };
  
  mmc2 {
 + interrupts-extended = intc 86 omap3_pmx_core 0x12e;
   vmmc-supply = vaux4;
   bus-width = 4;
   ti,non-removable;

I had 

+   interrupts-extended = intc 86 gpio5 5 0; /* GPIO_133 */
+   pinctrl-names = default, idle;
+   pinctrl-0 = mmc2_pins;
+   pinctrl-1 = mmc2_cirq_pin;

together with

+   mmc2_cirq_pin: pinmux_cirq_pin {
+   pinctrl-single,pins = 
+   OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT_PULLUP | MUX_MODE4) 
+   ;
+   };
+


and a longer definition for mmc2_pins.

Is that one line reconfigure the pin on demand?  How does that work?


Thanks,
NeilBrown


pgpJ6LLS5NdnN.pgp
Description: OpenPGP digital signature


Re: [PATCH 0/6] mmc: omap_hsmmc: simplify cover/card detect logic

2015-03-03 Thread NeilBrown
On Tue,  3 Mar 2015 13:28:12 +0100 Andreas Fenkart afenk...@gmail.com wrote:

 These patches are trying to clean up the cover/card detect logic.
 
   Mobile phones (some) have no card detect pin, but
   can detect if the cover is removed. The purpose is the
   same; detect if card is being added/removed, but the
   details differ.
   When the cover is removed, it does not mean the card is
   gone. But it might, since it is accessible now. It's like
   a warning. All the driver does is to limit write access to
   the card, see protect_card flag. In contrast, card detect
   notifies us after the fact, e.g. card is gone, card is
   inserted.
 
 While cover detect is only used by one platform (rx51), it
 complicates the card detect logic. By separating the code
 paths they both become easier to understand and maintain 
 
 Patches have been tested by reverting: 95bebb5696ab
 'mmc: omap_hsmmc: use mmc_of_parse to parse common mmc configuration'
 otherwise gpio detection is handled by mmc_of_parse

Wouldn't it make more sense to put this core  in mmc/core rather than in just
one host controller?  That way it would be available to all hosts, and you
wouldn't need to revert that patch.

NeilBrown


pgplTpnSDXJsy.pgp
Description: OpenPGP digital signature


Re: [PATCH] OMAP: DSS: DPI: disable vt-switch on suspend/resume.

2015-02-25 Thread NeilBrown
On Wed, 25 Feb 2015 12:03:36 +0200 Tomi Valkeinen tomi.valkei...@ti.com
wrote:

 On 25/02/15 11:37, NeilBrown wrote:
  
  These devices do not need to return to non-graphic console
  for suspend, so disable that option.
  This means there is less work to do in the suspend/resume cycle,
  making it smoother and cheaper.
  
  
  Signed-off-by: NeilBrown n...@brown.name
  
  --
  Hi Tomi,
   I wonder if you would consider this patch too.  It works for me and
  removes pointless vt switching.  I assume no-one would need or want that
  switching on suspend/resume but I guess I cannot be certain.
  
  Maybe a module-parameter could be used if there was any uncertainty.
 
 I was just yesterday picking patches from TI's kernel on top of
 mainline, and there's a similar one for omapfb and for omapdrm. Here's
 for omapfb:
 
 http://git.ti.com/android-sdk/kernel-video/commit/5915d8744c927307987b12b14bc6aa37b3bac05c?format=patch
 
 The patch in TI's kernel claims it's needed to make resume work. You're
 saying it just optimizes suspend/resume. I hadn't picked this up
 earlier, because I didn't understand why pm_set_vt_switch() would be
 needed to make resume work. And never had time to study it, so I still
 don't know what it's about...
 
 Looking at the drivers/tty/vt/vt_ioctl.c, it sounds to me that we should
 always do pm_set_vt_switch(0), as omapdss restores everything just fine
 on resume. Although it makes me wonder how it works if there are two
 display controllers, one needing the switch and the other not...

I wondered that too.  It would seem to make more sense for
pm_set_vt_switch(0) to be the default, that drivers which need the textmode
switch should call (1).  But I suspect there are historical reasons for the
current situation.

My experience is that suspend works just find without this setting, and I
don't even notice the vt switch, unless I have DEBUG_DRIVERS which slows
suspend/resume down so much (writing lots of test to a serial console) that
the transition is noticeable.
I made the patch because I think it is the right thing to do, rather than
because it fixed a particular symptom.

I suspect that if suspend doesn't work without this patch, then something very
different is being done in user-space.  Maybe some other display manager, not
X.  Maybe the X server is running on vt1 rather than vt7.



 
 Your patch does the call in a bit odd place, so I'll be queuing the
 patches for omapfb and omapdrm. Or actually, maybe the call could be
 done in one place in omapdss driver, as you do, but in omap_dsshw_probe().

I just figured that it had to be in some 'probe' function somewhere - I have
no opinion about which one (maybe all?-).  I'm perfectly happy with it
appearing anywhere that affects omap dss devices.

One thing I was reminded while testing and may as well mention:
I usually blank my display before suspending (using
FBIOBLANK/FB_BLANK_POWERDOWN ioctls).  However if I don't then I get a
warning:

[   87.261077] WARNING: CPU: 0 PID: 1901 at 
../drivers/video/fbdev/omap2/dss/dispc.c:558 dispc_mgr_go+0x20/0x8c()
[   87.261138] Modules linked in: ipv6 usb_f_ecm g_ether usb_f_rndis u_ether 
libcomposite configfs hso w1_bq27000 libertas_sdio libertas cfg80211 omap_hdq 
itg3200 ehci_omap ehci_hcd uio_pdrv_genirq uio
[   87.261169] CPU: 0 PID: 1901 Comm: Xorg Not tainted 4.0.0-rc1-gta04+ #538
[   87.261169] Hardware name: Generic OMAP36xx (Flattened Device Tree)
[   87.261199] [c00137e0] (unwind_backtrace) from [c00113a4] 
(show_stack+0x10/0x14)
[   87.261230] [c00113a4] (show_stack) from [c0033938] 
(warn_slowpath_common+0x80/0xa8)
[   87.261260] [c0033938] (warn_slowpath_common) from [c0033978] 
(warn_slowpath_null+0x18/0x1c)
[   87.261291] [c0033978] (warn_slowpath_null) from [c0232538] 
(dispc_mgr_go+0x20/0x8c)
[   87.261291] [c0232538] (dispc_mgr_go) from [c023e30c] 
(dss_set_go_bits+0xd4/0x100)
[   87.261322] [c023e30c] (dss_set_go_bits) from [c023f308] 
(omap_dss_mgr_apply+0x16c/0x1b8)
[   87.261352] [c023f308] (omap_dss_mgr_apply) from [c0250790] 
(omapfb_apply_changes+0x428/0x488)
[   87.261352] [c0250790] (omapfb_apply_changes) from [c0251024] 
(omapfb_set_par+0x74/0xb0)
[   87.261383] [c0251024] (omapfb_set_par) from [c02281a4] 
(fb_set_var+0x250/0x330)
[   87.261413] [c02281a4] (fb_set_var) from [c021fa24] 
(fbcon_blank+0x6c/0x260)
[   87.261444] [c021fa24] (fbcon_blank) from [c0275464] 
(do_unblank_screen+0xf8/0x19c)
[   87.261474] [c0275464] (do_unblank_screen) from [c026c268] 
(complete_change_console+0x50/0xcc)
[   87.261474] [c026c268] (complete_change_console) from [c026ccd8] 
(vt_ioctl+0x9f4/0x1238)
[   87.261505] [c026ccd8] (vt_ioctl) from [c02621e8] (tty_ioctl+0xc48/0xcac)
[   87.261535] [c02621e8] (tty_ioctl) from [c00dc344] 
(do_vfs_ioctl+0x5b0/0x61c)
[   87.261566] [c00dc344] (do_vfs_ioctl) from [c00dc3e4] 
(SyS_ioctl+0x34/0x58)
[   87.261566] [c00dc3e4] (SyS_ioctl) from [c000ea40] 
(ret_fast_syscall+0x0/0x34)

I think the Xserver is responding to a 'suspend' notification

Re: advanced LED controllers

2015-02-25 Thread NeilBrown
On Wed, 25 Feb 2015 22:49:41 +0100 Pavel Machek pa...@ucw.cz wrote:

 On Mon 2015-02-23 16:58:36, Felipe Balbi wrote:
  On Mon, Feb 23, 2015 at 11:34:57PM +0100, Pavel Machek wrote:
   On Thu 2015-02-19 15:14:24, Felipe Balbi wrote:
Hi,

Do we have support for LED controllers which can handle patterns of
different kinds ? I mean, currently, if we have an LED controller such
as TPIC2810 [1] which can control 8 different leds and each LED
corresponds to one bit on register 0x44, we could control leds by just
playing a wave file on the controller and create easy patterns with
that.
 
[1] http://www.ti.com/product/tpic2810

ps: tpic2810 is probably the simplest example, lp551, lp5523 and others
have even more advanced pattern engines which can even handle RGB leds.
   
   Well... some more advanced pattern engines can actually run code, up
   to and including prime number computation. So yes, this is complex,
   and how to handle it nicely is a question...
   
   I have notcc to compile for that.
  
  right, the point is that this is a solution which only works with lp5523
  and IMO linux led subsystem should do a little more for such devices.
 
 Well, question is what we want. Possibilities I see:
 
 1) We won't support all the features, just some common subset. Kernel
 will get commands for LED controller and translate them. Question is
 what reasonable subset is, then.
 
 I guess delay, set led brightness to X, jump would be minimal
 shared command set. lp5523 can do also slowly increase/decrease
 brightness to X (I believe we should support that one), arithmetics,
 conditional jumps, and communications between 3 threads.
 
 2) We want to support all the features. I guess that would mean doing
 compilation in userspace, and having compiler for each led
 controller. Having common source code would still be nice.
 
   Pavel

All (most) current options for controlling LEDs are based on what a user
might want, rather than what the hardware can provide.

I think it would be good to keep that approach, but add more interesting
functions which each hardware can support in whichever way suits it best.

So ramp_blink which allow a ramp on/off time to be specified would be
useful.

audio_meter which allows a particular sound card (or output or something)
to be specified would also be useful.  You could also specify a what volume
the LED saturates.
Then if you set each led on a given controller to saturate at different level
and to use the same sound  source, then you could get the graphic equaliser
effect.

Maybe 'blinking' should have a 'synchronise' setting to that a bunch of LEDs
can be synchonised so you can create a cylon eye effect.

i.e. don't focus on the low-level 'what can we provide' but on the high level
what might users want.

NeilBrown


pgpmXIEFj4kez.pgp
Description: OpenPGP digital signature


Re: [PATCH] OMAPDSS: restore name sysfs entry.

2015-02-25 Thread NeilBrown
On Wed, 25 Feb 2015 11:32:18 +0200 Tomi Valkeinen tomi.valkei...@ti.com
wrote:


 Yep, I don't think so. In any case, all this is to be deprecated, and as
 soon as omapdrm driver works reliably that should be the driver to use.

How close is that?  Is it worth experimenting yet?  Is there an xorg driver
available?  Maybe a wiki page telling me how to set it up?

http://processors.wiki.ti.com/index.php/Linux_Core_DSS_User%27s_Guide

seems to have some useful suggestions, but no mention of Xorg...

Thanks,
NeilBrown

 
 So of course we need to keep omapfb working for the years to come, but
 I'd rather not add any new sysfs files for a soon deprecated driver.
 
  Tomi
 
 



pgpYXnUpYaOd7.pgp
Description: OpenPGP digital signature


[PATCH] OMAP: DSS: DPI: disable vt-switch on suspend/resume.

2015-02-25 Thread NeilBrown

These devices do not need to return to non-graphic console
for suspend, so disable that option.
This means there is less work to do in the suspend/resume cycle,
making it smoother and cheaper.


Signed-off-by: NeilBrown n...@brown.name

--
Hi Tomi,
 I wonder if you would consider this patch too.  It works for me and
removes pointless vt switching.  I assume no-one would need or want that
switching on suspend/resume but I guess I cannot be certain.

Maybe a module-parameter could be used if there was any uncertainty.

thanks,
NeilBrown


diff --git a/drivers/video/fbdev/omap2/dss/dpi.c 
b/drivers/video/fbdev/omap2/dss/dpi.c
index f83e7b030249..4a29bab4ade3 100644
--- a/drivers/video/fbdev/omap2/dss/dpi.c
+++ b/drivers/video/fbdev/omap2/dss/dpi.c
@@ -32,6 +32,7 @@
 #include linux/string.h
 #include linux/of.h
 #include linux/clk.h
+#include linux/suspend.h
 
 #include video/omapdss.h
 
@@ -798,6 +799,8 @@ static int omap_dpi_probe(struct platform_device *pdev)
mutex_init(dpi-lock);
 
dpi_init_output(pdev);
+   /* No need to vt_switch in suspend/resume */
+   pm_set_vt_switch(0);
 
return 0;
 }


pgpuk4wfmxlqZ.pgp
Description: OpenPGP digital signature


Re: [PATCH] OMAPDSS: restore name sysfs entry.

2015-02-25 Thread NeilBrown
On Wed, 25 Feb 2015 10:49:58 +0200 Tomi Valkeinen tomi.valkei...@ti.com
wrote:

 Hi,
 
 On 24/02/15 22:31, NeilBrown wrote:
  On Tue, 24 Feb 2015 12:40:32 +0200 Tomi Valkeinen tomi.valkei...@ti.com
  wrote:
  
  Hi,
 
  On 24/02/15 11:37, NeilBrown wrote:
 
 
  commit 303e4697e762dc92a40405f4e4b8aac02cd0d70b
  OMAPDSS: rename display-sysfs 'name' entry
 
  broke the xorg X server on my device as it couldn't find the display
  any more.  It needs the 'name' file and now there isn't one.
 
  That commit claims that 'name' is not compatible with i2c or spi.
  i2c does register it own 'name' file, but spi does not, hence my
  problem - I have an spi display.
 
  So create a special case for i2c: add the name attribute for non-i2c
  devices.
 
 How about this patch instead. It separates the underlying device's sysfs 
 directory 
 from the displayX directory, and allows us to have name  display_name. So 
 it
 should work for any device type.
 
 
 From 8e411fa684d42fca35628b41837c6d72e87aaff0 Mon Sep 17 00:00:00 2001
 From: Tomi Valkeinen tomi.valkei...@ti.com
 Date: Wed, 25 Feb 2015 10:23:58 +0200
 Subject: [PATCH] OMAPDSS: fix regression with display sysfs files
 
 omapdss's sysfs directories for displays used to have 'name' file,
 giving the name for the display. This file was later renamed to
 'display_name' to avoid conflicts with i2c sysfs 'name' file. Looks like
 at least xserver-xorg-video-omap3 requires the 'name' file to be
 present.
 
 To fix the regression, this patch creates new kobjects for each display,
 allowing us to create sysfs directories for the displays. This way we
 have the whole directory for omapdss, and there will be no sysfs file
 clashes with the underlying display device's sysfs files.
 
 We can thus add the 'name' sysfs file back.
 
 Signed-off-by: Tomi Valkeinen tomi.valkei...@ti.com
 ---
  drivers/video/fbdev/omap2/dss/display-sysfs.c | 179 
 ++
  include/video/omapdss.h   |   1 +
  2 files changed, 96 insertions(+), 84 deletions(-)
 
 diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c 
 b/drivers/video/fbdev/omap2/dss/display-sysfs.c
 index 5a2095a98ed8..12186557a9d4 100644
 --- a/drivers/video/fbdev/omap2/dss/display-sysfs.c
 +++ b/drivers/video/fbdev/omap2/dss/display-sysfs.c
 @@ -28,44 +28,22 @@
  #include video/omapdss.h
  #include dss.h
  
 -static struct omap_dss_device *to_dss_device_sysfs(struct device *dev)
 +static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
  {
 - struct omap_dss_device *dssdev = NULL;
 -
 - for_each_dss_dev(dssdev) {
 - if (dssdev-dev == dev) {
 - omap_dss_put_device(dssdev);
 - return dssdev;
 - }
 - }
 -
 - return NULL;
 -}
 -
 -static ssize_t display_name_show(struct device *dev,
 - struct device_attribute *attr, char *buf)
 -{
 - struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
 -
   return snprintf(buf, PAGE_SIZE, %s\n,
   dssdev-name ?
   dssdev-name : );
  }
  
 -static ssize_t display_enabled_show(struct device *dev,
 - struct device_attribute *attr, char *buf)
 +static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char 
 *buf)
  {
 - struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
 -
   return snprintf(buf, PAGE_SIZE, %d\n,
   omapdss_device_is_enabled(dssdev));
  }
  
 -static ssize_t display_enabled_store(struct device *dev,
 - struct device_attribute *attr,
 +static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
   const char *buf, size_t size)
  {
 - struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
   int r;
   bool enable;
  
 @@ -90,19 +68,16 @@ static ssize_t display_enabled_store(struct device *dev,
   return size;
  }
  
 -static ssize_t display_tear_show(struct device *dev,
 - struct device_attribute *attr, char *buf)
 +static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
  {
 - struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
   return snprintf(buf, PAGE_SIZE, %d\n,
   dssdev-driver-get_te ?
   dssdev-driver-get_te(dssdev) : 0);
  }
  
 -static ssize_t display_tear_store(struct device *dev,
 - struct device_attribute *attr, const char *buf, size_t size)
 +static ssize_t display_tear_store(struct omap_dss_device *dssdev,
 + const char *buf, size_t size)
  {
 - struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
   int r;
   bool te;
  
 @@ -120,10 +95,8 @@ static ssize_t display_tear_store(struct device *dev,
   return size;
  }
  
 -static ssize_t display_timings_show(struct device *dev,
 - struct device_attribute *attr, char *buf)
 +static ssize_t display_timings_show(struct omap_dss_device *dssdev, char 
 *buf)
  {
 - struct

Re: [PATCH] OMAPDSS: restore name sysfs entry.

2015-02-24 Thread NeilBrown
On Tue, 24 Feb 2015 12:40:32 +0200 Tomi Valkeinen tomi.valkei...@ti.com
wrote:

 Hi,
 
 On 24/02/15 11:37, NeilBrown wrote:
  
  
  commit 303e4697e762dc92a40405f4e4b8aac02cd0d70b
  OMAPDSS: rename display-sysfs 'name' entry
  
  broke the xorg X server on my device as it couldn't find the display
  any more.  It needs the 'name' file and now there isn't one.
  
  That commit claims that 'name' is not compatible with i2c or spi.
  i2c does register it own 'name' file, but spi does not, hence my
  problem - I have an spi display.
  
  So create a special case for i2c: add the name attribute for non-i2c
  devices.
 
 What X driver is that? What's it doing with the display name? Is it just
 using the display name to show something for the user, and the returned
 value can be essentially any string?
 
  Tomi
 
 
/usr/lib/xorg/modules/drivers/omapfb_drv.so
from package xserver-xorg-video-omap3 in Debian.

I don't know where the main upstream source is, but here:

https://gitorious.org/gnutoo-s-programs-for-shr/xf86-video-omapfb/source/28c006c94e57ea71df11ec4fff79d7ffcfc4860f:src/omapfb-output-dss.c#L258

is the code which reads
   /sys/devices/platform/omapdss/display0/name
and fails if that file cannot be opened.

Thanks,
NeilBrown


pgpU5K5ew1vFC.pgp
Description: OpenPGP digital signature


[PATCH 09/15] twl4030_charger: allow max_current to be managed via sysfs.

2015-02-24 Thread NeilBrown
'max_current' sysfs attributes are created which allow the
max to be set.
Whenever a current source changes, the default is restored.
This will be followed by a uevent, so user-space can decide to
update again.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   76 +++
 1 file changed, 76 insertions(+)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index bfc9b808301e..b0242786d047 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -473,6 +473,8 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void 
*arg)
struct twl4030_bci *bci = arg;
 
dev_dbg(bci-dev, CHG_PRES irq\n);
+   /* reset current on each 'plug' event */
+   bci-ac_cur = 50;
twl4030_charger_update_current(bci);
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
@@ -527,6 +529,67 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void 
*arg)
return IRQ_HANDLED;
 }
 
+/*
+ * sysfs max_current store
+ */
+static ssize_t
+twl4030_bci_max_current_store(struct device *dev, struct device_attribute 
*attr,
+   const char *buf, size_t n)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int cur = 0;
+   int status = 0;
+   status = kstrtoint(buf, 10, cur);
+   if (status)
+   return status;
+   if (cur  0)
+   return -EINVAL;
+   if (dev == bci-ac.dev) {
+   if (bci-ac_cur == cur)
+   return n;
+   bci-ac_cur = cur;
+   } else {
+   if (bci-usb_cur == cur)
+   return n;
+   bci-usb_cur = cur;
+   }
+   twl4030_charger_update_current(bci);
+   return (status == 0) ? n : status;
+}
+
+/*
+ * sysfs max_current show
+ */
+static ssize_t twl4030_bci_max_current_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   int status = 0;
+   int cur = -1;
+   u8 bcictl1;
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+
+   if (dev == bci-ac.dev) {
+   if (!bci-ac_is_active)
+   cur = bci-ac_cur;
+   } else {
+   if (bci-ac_is_active)
+   cur = bci-usb_cur;
+   }
+   if (cur  0) {
+   cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
+   if (cur  0)
+   return cur;
+   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
+   if (status  0)
+   return status;
+   cur = regval2ua(cur, bcictl1  TWL4030_CGAIN);
+   }
+   return scnprintf(buf, PAGE_SIZE, %u\n, cur);
+}
+
+static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show,
+   twl4030_bci_max_current_store);
+
 static void twl4030_bci_usb_work(struct work_struct *data)
 {
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
@@ -549,6 +612,12 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
 
dev_dbg(bci-dev, OTG notify %lu\n, val);
 
+   /* reset current on each 'plug' event */
+   if (allow_usb)
+   bci-usb_cur = 50;
+   else
+   bci-usb_cur = 10;
+
bci-event = val;
schedule_work(bci-work);
 
@@ -809,6 +878,11 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
dev_warn(pdev-dev, failed to unmask interrupts: %d\n, ret);
 
twl4030_charger_update_current(bci);
+   if (device_create_file(bci-usb.dev, dev_attr_max_current))
+   dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-ac.dev, dev_attr_max_current))
+   dev_warn(pdev-dev, could not create sysfs file\n);
+
twl4030_charger_enable_ac(true);
if (!IS_ERR_OR_NULL(bci-transceiver))
twl4030_bci_usb_ncb(bci-usb_nb,
@@ -836,6 +910,8 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
twl4030_charger_enable_usb(bci, false);
twl4030_charger_enable_backup(0, 0);
 
+   device_remove_file(bci-usb.dev, dev_attr_max_current);
+   device_remove_file(bci-ac.dev, dev_attr_max_current);
/* mask interrupts */
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR1A);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 15/15] twl4030_charger: assume a 'charger' can supply maximum current.

2015-02-24 Thread NeilBrown
If it cannot, we will stop pulling more current when voltage drops.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 7ad6b4b531d7..89e2c121dd22 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -691,8 +691,10 @@ static void twl4030_bci_usb_work(struct work_struct *data)
struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
 
switch (bci-event) {
-   case USB_EVENT_VBUS:
case USB_EVENT_CHARGER:
+   bci-usb_cur = USB_MAX_CURRENT;
+   /* FALL THROUGH */
+   case USB_EVENT_VBUS:
case USB_EVENT_ENUMERATED:
twl4030_charger_enable_usb(bci, true);
break;


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 14/15] twl4030_charger: Increase current carefully while watching voltage.

2015-02-24 Thread NeilBrown
The USB Battery Charging spec (BC1.2) suggests a dedicated
charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25
volts.

To choose the correct current voltage setting requires a trial
and error approach: try to draw current and see if the voltage drops
too low.

Even with a configure Standard Downstream Port, it may not be possible
to reliably pull 500mA - depending on cable quality and source
quality I have reports of charging failure due to the voltage dropping
too low.

To address both these concern, this patch introduce incremental
current setting.
The current pull from VBUS is increased in steps of 20mA every 100ms
until the target is reached or until the measure voltage drops below
4.75V.  If the voltage does go too long, the target current is reduced
by 20mA and kept there.

This applies to currents selected automatically, or to values
set via sysfs.  So setting a large value will cause the maximum
available to be used - up to the limit of 1.7mA imposed by the
hardware.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   54 ++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index e5a0225ea87e..7ad6b4b531d7 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -117,6 +117,18 @@ struct twl4030_bci {
 #defineCHARGE_AUTO 1
 #defineCHARGE_LINEAR   2
 
+   /* When setting the USB current we slowly increase the
+* requested current until target is reached or the voltage
+* drops below 4.75V.  In the latter case we set back one
+* step.
+*/
+   int usb_cur_actual;
+   struct delayed_work current_worker;
+#defineUSB_CUR_STEP2   /* 20mA at a time */
+#defineUSB_MIN_VOLT475 /* 4.75V */
+#defineUSB_CUR_DELAY   msecs_to_jiffies(100)
+#defineUSB_MAX_CURRENT 170 /* TWL4030 caps at 1.7mA */
+
unsigned long   event;
 };
 
@@ -249,8 +261,14 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
cur = bci-ac_cur;
bci-ac_is_active = 1;
} else {
-   cur = bci-usb_cur;
+   cur = bci-usb_cur_actual;
bci-ac_is_active = 0;
+   if (cur  bci-usb_cur) {
+   cur = bci-usb_cur;
+   bci-usb_cur_actual = cur;
+   }
+   if (cur  bci-usb_cur)
+   schedule_delayed_work(bci-current_worker, 
USB_CUR_DELAY);
}
 
/* First, check thresholds and see if cgain is needed */
@@ -379,6 +397,38 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
return 0;
 }
 
+static void twl4030_current_worker(struct work_struct *data)
+{
+   int v;
+   int res;
+   struct twl4030_bci *bci = container_of(data, struct twl4030_bci,
+  current_worker.work);
+
+   res = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
+   if (res  0)
+   v = 0;
+   else
+   /* BCIVBUS uses ADCIN8, 7/1023 V/step */
+   v = res * 6843;
+
+   printk(v=%d cur=%d target=%d\n, v, bci-usb_cur_actual,
+  bci-usb_cur);
+
+   if (v  USB_MIN_VOLT) {
+   /* Back up and stop adjusting. */
+   bci-usb_cur_actual -= USB_CUR_STEP;
+   bci-usb_cur = bci-usb_cur_actual;
+   } else if (bci-usb_cur_actual = bci-usb_cur ||
+  bci-usb_cur_actual + USB_CUR_STEP  USB_MAX_CURRENT) {
+   /* Reach target and volts are OK - stop */
+   return;
+   } else {
+   bci-usb_cur_actual += USB_CUR_STEP;
+   schedule_delayed_work(bci-current_worker, USB_CUR_DELAY);
+   }
+   twl4030_charger_update_current(bci);
+}
+
 /*
  * Enable/Disable USB Charge functionality.
  */
@@ -441,6 +491,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
pm_runtime_put_autosuspend(bci-transceiver-dev);
bci-usb_enabled = 0;
}
+   bci-usb_cur_actual = 0;
}
 
return ret;
@@ -972,6 +1023,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
}
 
INIT_WORK(bci-work, twl4030_bci_usb_work);
+   INIT_DELAYED_WORK(bci-current_worker, twl4030_current_worker);
 
bci-usb_nb.notifier_call = twl4030_bci_usb_ncb;
if (bci-dev-of_node) {


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 10/15] twl4030_charger: only draw USB current as negotiated with host.

2015-02-24 Thread NeilBrown
If the phy has been told what current it can draw, it tells us
and now we use that number.

Note that 'vbus_draw' is in mA, while usb_cur is in uA.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index b0242786d047..01090a440583 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -597,6 +597,7 @@ static void twl4030_bci_usb_work(struct work_struct *data)
switch (bci-event) {
case USB_EVENT_VBUS:
case USB_EVENT_CHARGER:
+   case USB_EVENT_ENUMERATED:
twl4030_charger_enable_usb(bci, true);
break;
case USB_EVENT_NONE:
@@ -609,6 +610,7 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
   void *priv)
 {
struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, usb_nb);
+   unsigned *vbus_draw = priv;
 
dev_dbg(bci-dev, OTG notify %lu\n, val);
 
@@ -619,6 +621,9 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
bci-usb_cur = 10;
 
bci-event = val;
+   if (val == USB_EVENT_ENUMERATED  vbus_draw 
+   *vbus_draw * 1000  bci-usb_cur)
+   bci-usb_cur = *vbus_draw * 1000;
schedule_work(bci-work);
 
return NOTIFY_OK;


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 11/15] twl4030_charger: enable manual enable/disable of usb charging.

2015-02-24 Thread NeilBrown
'off' or 'auto' to

 /sys/class/power/twl4030_usb/mode

will now enable or disable charging from USB port.  Normally this is
enabled on 'plug' and disabled on 'unplug'.
Unplug will still disable charging.  'plug' will only enable it if
'auto' if selected.

Signed-off-by: NeilBrown ne...@suse.de

Conflicts:
drivers/power/twl4030_charger.c
---
 drivers/power/twl4030_charger.c |   57 +++
 1 file changed, 57 insertions(+)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 01090a440583..19e8dbb1303e 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -107,6 +107,9 @@ struct twl4030_bci {
int ichg_eoc, ichg_lo, ichg_hi;
int usb_cur, ac_cur;
boolac_is_active;
+   int usb_mode; /* charging mode requested */
+#defineCHARGE_OFF  0
+#defineCHARGE_AUTO 1
 
unsigned long   event;
 };
@@ -377,6 +380,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 {
int ret;
 
+   if (bci-usb_mode == CHARGE_OFF)
+   enable = false;
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
 
twl4030_charger_update_current(bci);
@@ -629,6 +634,54 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
return NOTIFY_OK;
 }
 
+/*
+ * sysfs charger enabled store
+ */
+static char *modes[] = { off, auto };
+static ssize_t
+twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int mode;
+   int status;
+
+   if (sysfs_streq(buf, modes[0]))
+   mode = 0;
+   else if (sysfs_streq(buf, modes[1]))
+   mode = 1;
+   else
+   return -EINVAL;
+   twl4030_charger_enable_usb(bci, false);
+   bci-usb_mode = mode;
+   status = twl4030_charger_enable_usb(bci, true);
+   return (status == 0) ? n : status;
+}
+
+/*
+ * sysfs charger enabled show
+ */
+static ssize_t
+twl4030_bci_mode_show(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+   struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
+   int len = 0;
+   int i;
+
+   for (i = 0; i  ARRAY_SIZE(modes); i++)
+   if (bci-usb_mode == i)
+   len += snprintf(buf+len, PAGE_SIZE-len,
+   [%s] , modes[i]);
+   else
+   len += snprintf(buf+len, PAGE_SIZE-len,
+   %s , modes[i]);
+   buf[len-1] = '\n';
+   return len;
+}
+static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show,
+  twl4030_bci_mode_store);
+
 static int twl4030_charger_get_current(void)
 {
int curr;
@@ -799,6 +852,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
bci-usb_cur = 50;  /* 500mA */
else
bci-usb_cur = 10;  /* 100mA */
+   bci-usb_mode = CHARGE_AUTO;
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);
@@ -885,6 +939,8 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
twl4030_charger_update_current(bci);
if (device_create_file(bci-usb.dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-usb.dev, dev_attr_mode))
+   dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-ac.dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
 
@@ -917,6 +973,7 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
 
device_remove_file(bci-usb.dev, dev_attr_max_current);
device_remove_file(bci-ac.dev, dev_attr_max_current);
+   device_remove_file(bci-usb.dev, dev_attr_mode);
/* mask interrupts */
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR1A);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 12/15] twl4030_charger: add software controlled linear charging mode.

2015-02-24 Thread NeilBrown
Add a 'continuous' option for usb charging which enabled
the linear charging mode of the twl4030.

Linear charging does a good job with not so reliable power sources, since
several voltage controlling is then often too intelligent.
It was used with a bike hub dynamo since a year or so. In that case there
are automatically charging stops when the cyclist needs a break.

Orignal-by: Andreas Kemnade andr...@kemnade.info
Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   57 ---
 1 file changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 19e8dbb1303e..6c53f0b601a4 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -24,6 +24,8 @@
 #include linux/usb/otg.h
 #include linux/i2c/twl4030-madc.h
 
+#define TWL4030_BCIMDEN0x00
+#define TWL4030_BCIMDKEY   0x01
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
 #define TWL4030_BCIVAC 0x0a
@@ -35,13 +37,16 @@
 #define TWL4030_BCIIREF1   0x27
 #define TWL4030_BCIIREF2   0x28
 #define TWL4030_BCIMFKEY   0x11
+#define TWL4030_BCIMFEN3   0x14
 #define TWL4030_BCIMFTH8   0x1d
 #define TWL4030_BCIMFTH9   0x1e
+#define TWL4030_BCIWDKEY   0x21
 
 #define TWL4030_BCIMFSTS1  0x01
 
 #define TWL4030_BCIAUTOWEN BIT(5)
 #define TWL4030_CONFIG_DONEBIT(4)
+#define TWL4030_CVENAC BIT(2)
 #define TWL4030_BCIAUTOUSB BIT(1)
 #define TWL4030_BCIAUTOAC  BIT(0)
 #define TWL4030_CGAIN  BIT(5)
@@ -110,6 +115,7 @@ struct twl4030_bci {
int usb_mode; /* charging mode requested */
 #defineCHARGE_OFF  0
 #defineCHARGE_AUTO 1
+#defineCHARGE_LINEAR   2
 
unsigned long   event;
 };
@@ -392,16 +398,44 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
bci-usb_enabled = 1;
}
 
-   /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
-   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
-   if (ret  0)
-   return ret;
+   if (bci-usb_mode == CHARGE_AUTO) {
+   /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
+   twl4030_clear_set_boot_bci(0, 
TWL4030_BCIAUTOAC|TWL4030_CVENAC);
+   }
 
/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
+   if (bci-usb_mode == CHARGE_LINEAR) {
+   
twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0);
+   /* Watch dog key: WOVF acknowledge */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
+  TWL4030_BCIWDKEY);
+   /* 0x24 + EKEY6:  off mode */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
+  TWL4030_BCIMDKEY);
+   /* EKEY2: Linear charge: usb path */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
+  TWL4030_BCIMDKEY);
+   /* WDKEY5: stop watchdog count */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
+  TWL4030_BCIWDKEY);
+   /* enable MFEN3 access */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c,
+  TWL4030_BCIMFKEY);
+/* ICHGEOCEN - end-of-charge monitor (current  80mA)
+ *  (charging continues)
+ * ICHGLOWEN - current level monitor (charge continues)
+ * don't monitor over-current or heat save
+ */
+   ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf0,
+  TWL4030_BCIMFEN3);
+   }
} else {
ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
+   ret |= twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
+   TWL4030_BCIMDKEY);
if (bci-usb_enabled) {
pm_runtime_mark_last_busy(bci-transceiver-dev);
pm_runtime_put_autosuspend(bci-transceiver-dev);
@@ -637,7 +671,7 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
 /*
  * sysfs charger enabled store
  */
-static char *modes[] = { off, auto };
+static char

[PATCH 13/15] twl4030_charger: add ac/mode to match usb/mode

2015-02-24 Thread NeilBrown
This allows AC charging to be turned off, much like usb charging.

continuous (aka linear) mode maps to the CVENAC (constant voltage)
feature of the twl4030.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   40 +--
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 6c53f0b601a4..e5a0225ea87e 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -112,7 +112,7 @@ struct twl4030_bci {
int ichg_eoc, ichg_lo, ichg_hi;
int usb_cur, ac_cur;
boolac_is_active;
-   int usb_mode; /* charging mode requested */
+   int usb_mode, ac_mode; /* charging mode requested */
 #defineCHARGE_OFF  0
 #defineCHARGE_AUTO 1
 #defineCHARGE_LINEAR   2
@@ -449,12 +449,18 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 /*
  * Enable/Disable AC Charge funtionality.
  */
-static int twl4030_charger_enable_ac(bool enable)
+static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable)
 {
int ret;
 
-   if (enable)
-   ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
+   if (bci-ac_mode == CHARGE_OFF)
+   enable = false;
+
+   if (enable  bci-ac_mode == CHARGE_LINEAR)
+   ret = twl4030_clear_set_boot_bci(0, (TWL4030_CVENAC |
+TWL4030_BCIAUTOAC));
+   else if (enable)
+   ret = twl4030_clear_set_boot_bci(TWL4030_CVENAC, 
TWL4030_BCIAUTOAC);
else
ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC, 0);
 
@@ -688,9 +694,15 @@ twl4030_bci_mode_store(struct device *dev, struct 
device_attribute *attr,
mode = 2;
else
return -EINVAL;
-   twl4030_charger_enable_usb(bci, false);
-   bci-usb_mode = mode;
-   status = twl4030_charger_enable_usb(bci, true);
+   if (dev == bci-ac.dev) {
+   twl4030_charger_enable_ac(bci, false);
+   bci-ac_mode = mode;
+   status = twl4030_charger_enable_ac(bci, true);
+   } else {
+   twl4030_charger_enable_usb(bci, false);
+   bci-usb_mode = mode;
+   status = twl4030_charger_enable_usb(bci, true);
+   }
return (status == 0) ? n : status;
 }
 
@@ -704,9 +716,13 @@ twl4030_bci_mode_show(struct device *dev,
struct twl4030_bci *bci = dev_get_drvdata(dev-parent);
int len = 0;
int i;
+   int mode = bci-usb_mode;
+
+   if (dev == bci-ac.dev)
+   mode = bci-ac_mode;
 
for (i = 0; i  ARRAY_SIZE(modes); i++)
-   if (bci-usb_mode == i)
+   if (mode == i)
len += snprintf(buf+len, PAGE_SIZE-len,
[%s] , modes[i]);
else
@@ -900,6 +916,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
else
bci-usb_cur = 10;  /* 100mA */
bci-usb_mode = CHARGE_AUTO;
+   bci-ac_mode = CHARGE_AUTO;
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);
@@ -988,10 +1005,12 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-usb.dev, dev_attr_mode))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(bci-ac.dev, dev_attr_mode))
+   dev_warn(pdev-dev, could not create sysfs file\n);
if (device_create_file(bci-ac.dev, dev_attr_max_current))
dev_warn(pdev-dev, could not create sysfs file\n);
 
-   twl4030_charger_enable_ac(true);
+   twl4030_charger_enable_ac(bci, true);
if (!IS_ERR_OR_NULL(bci-transceiver))
twl4030_bci_usb_ncb(bci-usb_nb,
bci-transceiver-last_event,
@@ -1014,13 +1033,14 @@ static int __exit twl4030_bci_remove(struct 
platform_device *pdev)
 {
struct twl4030_bci *bci = platform_get_drvdata(pdev);
 
-   twl4030_charger_enable_ac(false);
+   twl4030_charger_enable_ac(bci, false);
twl4030_charger_enable_usb(bci, false);
twl4030_charger_enable_backup(0, 0);
 
device_remove_file(bci-usb.dev, dev_attr_max_current);
device_remove_file(bci-ac.dev, dev_attr_max_current);
device_remove_file(bci-usb.dev, dev_attr_mode);
+   device_remove_file(bci-ac.dev, dev_attr_mode);
/* mask interrupts */
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR1A);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message

[PATCH] OMAPDSS: restore name sysfs entry.

2015-02-24 Thread NeilBrown


commit 303e4697e762dc92a40405f4e4b8aac02cd0d70b
OMAPDSS: rename display-sysfs 'name' entry

broke the xorg X server on my device as it couldn't find the display
any more.  It needs the 'name' file and now there isn't one.

That commit claims that 'name' is not compatible with i2c or spi.
i2c does register it own 'name' file, but spi does not, hence my
problem - I have an spi display.

So create a special case for i2c: add the name attribute for non-i2c
devices.

Fixes: 303e4697e762dc92a40405f4e4b8aac02cd0d70b
Signed-off-by: NeilBrown ne...@suse.de

--

Hi Tomi,
 I wonder if you would consider this for the next merge window (or maybe even 
sooner as a bug-fix).
I haven't tested it with an i2c display, but it certainly allows xorg to work
on my spi-attached display.

Thanks,
NeilBrown


diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c 
b/drivers/video/fbdev/omap2/dss/display-sysfs.c
index 5a2095a98ed8..53897b743130 100644
--- a/drivers/video/fbdev/omap2/dss/display-sysfs.c
+++ b/drivers/video/fbdev/omap2/dss/display-sysfs.c
@@ -25,6 +25,15 @@
 #include linux/platform_device.h
 #include linux/sysfs.h
 
+#if IS_ENABLED(CONFIG_I2C)
+#include linux/i2c.h
+#else
+static inline int i2c_verify_client(struct device *dev)
+{
+   return NULL;
+}
+#endif
+
 #include video/omapdss.h
 #include dss.h
 
@@ -278,6 +287,7 @@ static ssize_t display_wss_store(struct device *dev,
 }
 
 static DEVICE_ATTR(display_name, S_IRUGO, display_name_show, NULL);
+static DEVICE_ATTR(name, S_IRUGO, display_name_show, NULL);
 static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
display_enabled_show, display_enabled_store);
 static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
@@ -315,6 +325,17 @@ int display_init_sysfs(struct platform_device *pdev)
DSSERR(failed to create sysfs files\n);
goto err;
}
+   if (!i2c_verify_client(dssdev-dev)) {
+   /*
+* Add 'name' file - not compatible with i2c, but
+* need by Xorg for other devices.
+*/
+   r = sysfs_create_file(kobj, dev_attr_name.attr);
+   if (r) {
+   DSSERR(fail to create 'name' sysfs file\n);
+   goto err;
+   }
+   }
 
r = sysfs_create_link(pdev-dev.kobj, kobj, dssdev-alias);
if (r) {
@@ -341,5 +362,7 @@ void display_uninit_sysfs(struct platform_device *pdev)
sysfs_remove_link(pdev-dev.kobj, dssdev-alias);
sysfs_remove_files(dssdev-dev-kobj,
display_sysfs_attrs);
+   sysfs_remove_file(dssdev-dev-kobj,
+ dev_attr_name.attr);
}
 }


pgpkhJV_A17Yn.pgp
Description: OpenPGP digital signature


[PATCH 1/4] mmc: core: fold mmc_set_bus_width calls into sdio_enable_4bit_bus.

2015-02-23 Thread NeilBrown
Every call to sdio_enable_4bit_bus is followed (on success) but a call
to mmc_set_bus_width().

To simplify the code, include those calls directly in
sdio_enable_4bit_bus().

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/core/sdio.c |   32 
 1 file changed, 12 insertions(+), 20 deletions(-)

diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index ce6cc47206b0..5bc6c7dbbd60 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)
int err;
 
if (card-type == MMC_TYPE_SDIO)
-   return sdio_enable_wide(card);
-
-   if ((card-host-caps  MMC_CAP_4_BIT_DATA) 
-   (card-scr.bus_widths  SD_SCR_BUS_WIDTH_4)) {
+   err = sdio_enable_wide(card);
+   else if ((card-host-caps  MMC_CAP_4_BIT_DATA) 
+(card-scr.bus_widths  SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
if (err)
return err;
+   err = sdio_enable_wide(card);
+   if (err = 0)
+   mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
} else
return 0;
 
-   err = sdio_enable_wide(card);
-   if (err = 0)
-   mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
+   if (err  0) {
+   mmc_set_bus_width(card-host, MMC_BUS_WIDTH_4);
+   err = 0;
+   }
 
return err;
 }
@@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
/*
 * Switch to wider bus (if supported).
 */
-   if (card-host-caps  MMC_CAP_4_BIT_DATA) {
+   if (card-host-caps  MMC_CAP_4_BIT_DATA)
err = sdio_enable_4bit_bus(card);
-   if (err  0) {
-   mmc_set_bus_width(card-host, MMC_BUS_WIDTH_4);
-   err = 0;
-   }
-   }
 
/* Set the driver strength for the card */
sdio_select_driver_type(card);
@@ -803,9 +801,7 @@ try_again:
 * Switch to wider bus (if supported).
 */
err = sdio_enable_4bit_bus(card);
-   if (err  0)
-   mmc_set_bus_width(card-host, MMC_BUS_WIDTH_4);
-   else if (err)
+   if (err)
goto remove;
}
 finish:
@@ -983,10 +979,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
} else if (mmc_card_keep_power(host)  mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host-card);
-   if (err  0) {
-   mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
-   err = 0;
-   }
}
 
if (!err  host-sdio_irqs) {


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/4] mmc: omap_hsmmc: switch to 1-bit before stopping clocks.

2015-02-23 Thread NeilBrown
Make use of the new mmc_sdio_want_no_clocks() call to avoid stopping
clocks while SD Card interrupts are enabled and we aren't in
1-bit mode.

Also stop clocks immediately in omap_hsmmc_disable_fclk() if
1-bit mode has been entered for this purpose.

With this, I can use my libertas wifi with a 4-bit bus, with
interrupts and runtime power-management enabled, and get around
14Mb/sec throughput (which is the best I've seen).

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/host/omap_hsmmc.c |   13 ++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f84cfb01716d..14fce3b92633 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1791,9 +1791,12 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
 {
struct omap_hsmmc_host *host = mmc_priv(mmc);
 
-   pm_runtime_mark_last_busy(host-dev);
-   pm_runtime_put_autosuspend(host-dev);
-
+   if (atomic_read(mmc-sdio_narrowed) == 2)
+   pm_runtime_put_sync(host-dev);
+   else {
+   pm_runtime_mark_last_busy(host-dev);
+   pm_runtime_put_autosuspend(host-dev);
+   }
return 0;
 }
 
@@ -2311,6 +2314,10 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
spin_lock_irqsave(host-irq_lock, flags);
if ((host-mmc-caps  MMC_CAP_SDIO_IRQ) 
(host-flags  HSMMC_SDIO_IRQ_ENABLED)) {
+   if (mmc_sdio_want_no_clocks(host-mmc) == 0) {
+   ret = -EBUSY;
+   goto abort;
+   }
/* disable sdio irq handling to prevent race */
OMAP_HSMMC_WRITE(host-base, ISE, 0);
OMAP_HSMMC_WRITE(host-base, IE, 0);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/4] mmc: core: allow non-blocking form of mmc_claim_host

2015-02-23 Thread NeilBrown
Change the handling for the 'abort' flag so that if
it is set, but we can claim the host, then do the claim,
rather than aborting.

When the abort is async this just means that a race between aborting
an allowing a claim is resolved slightly differently.  Any
code must already be able to handle 'abort' being set just as the host
is claimed.

This allows extra functionality.  If __mmc_claim_host() is called
with an 'abort' pointer which is initialized to '1', it will effect a
non-blocking 'claim'.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/core/core.c |3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 23f10f72e5f3..541c8903dc6b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -912,10 +912,11 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t 
*abort)
spin_lock_irqsave(host-lock, flags);
}
set_current_state(TASK_RUNNING);
-   if (!stop) {
+   if (!host-claimed || host-claimer == current) {
host-claimed = 1;
host-claimer = current;
host-claim_cnt += 1;
+   stop = 0;
} else
wake_up(host-wq);
spin_unlock_irqrestore(host-lock, flags);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/4] Switch to 1-bit mode SDIO before disabling clocks.

2015-02-23 Thread NeilBrown
This is a reworking of this code that I promised at the end of
January.

SDIO interrupt in 4-bit mode require the clock to be running.  So we
need to switch to 1-bit mode before turning off the clock.

This series provides infrastructure in mmc-core, and adds the
functionality to omap_hsmmc.

Thanks,
NeilBrown


---

NeilBrown (4):
  mmc: core: fold mmc_set_bus_width calls into sdio_enable_4bit_bus.
  mmc: core: allow non-blocking form of mmc_claim_host
  mmc: sdio: support switching to 1-bit before turning off clocks
  mmc: omap_hsmmc: switch to 1-bit before stopping clocks.


 drivers/mmc/core/core.c   |   21 +---
 drivers/mmc/core/sdio.c   |   74 +
 drivers/mmc/host/omap_hsmmc.c |   13 ++-
 include/linux/mmc/core.h  |2 +
 include/linux/mmc/host.h  |2 +
 5 files changed, 83 insertions(+), 29 deletions(-)

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/4] mmc: sdio: support switching to 1-bit before turning off clocks

2015-02-23 Thread NeilBrown
According to section 7.1.2 of

http://www.sandisk.com/media/File/OEM/Manuals/SD_SDIO_specsv1.pdf

In the case where the interrupt mechanism is used to wake the host while
the card is in a low power state (i.e. no clocks), Both the card and the
host shall be placed into the 1-bit SD mode prior to stopping the clock.

This is particularly important for the Marvell libertas wifi chip
in the GTA04.  While in 4-bit mode it will only signal an interrupt
when the clock is running (which is why setting CLKEXTFREE is
important).
In 1-bit mode, the interrupt is asynchronous (explained in OMAP3
TRM description of the CIRQ flag to MMCHS_STAT:

  In 1-bit mode, interrupt source is asynchronous (can be a source of
  asynchronous wakeup).
  In 4-bit mode, interrupt source is sampled during the interrupt
  cycle.

)

It is awkward to simply set 1-bit mode in -runtime_suspend
as that will call mmc_set_ios which calls ops-set_ios(),
which will likely call pm_runtime_get_sync(), on the device that
is currently suspending.  This deadlocks.

So:
 - create a work_struct to schedule setting of 1-bit mode
 - introduce an 'sdio_narrowed' state flag which transitions:
 0 (normal) - 1 (convert to 1-bit pending) -
 2 (have switch to 1-bit mode) - 0 (normal)
 - create a function mmc_sdio_want_no_clocks() which can be called
   when the driver wants to turn off clocks (presumably after an
   idle timeout).  This either succeeds (in 1-bit mode) or fails
   and schedules the work to switch to 1-bit mode.
 - when the host is claimed, if sdio_narrowed is 2, restore the
   4-bit bus
 - When the host is released, if sdio_narrowed is 1, then some
   caller other  than our worker claimed the host first, so
   clear sdio_narrowed.

This all allows a graceful and race-free switch to 1-bit mode
before switching off the clocks, if SDIO interrupts are enabled.

A host should call mmc_sdio_want_no_clocks() when about to turn off
clocks if sdio interrupts are enabled, and the -disable() function
should not use a timeout (pm_runtime_put_autosuspend) if
-sdio_narrowed is 2.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/core/core.c  |   18 ++
 drivers/mmc/core/sdio.c  |   42 +-
 include/linux/mmc/core.h |2 ++
 include/linux/mmc/host.h |2 ++
 4 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 541c8903dc6b..0258fdf1a03d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -921,8 +921,14 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t 
*abort)
wake_up(host-wq);
spin_unlock_irqrestore(host-lock, flags);
remove_wait_queue(host-wq, wait);
-   if (host-ops-enable  !stop  host-claim_cnt == 1)
-   host-ops-enable(host);
+   if (!stop  host-claim_cnt == 1) {
+   if (host-ops-enable)
+   host-ops-enable(host);
+   if (atomic_read(host-sdio_narrowed) == 2) {
+   sdio_enable_4bit_bus(host-card);
+   atomic_set(host-sdio_narrowed, 0);
+   }
+   }
return stop;
 }
 
@@ -941,8 +947,12 @@ void mmc_release_host(struct mmc_host *host)
 
WARN_ON(!host-claimed);
 
-   if (host-ops-disable  host-claim_cnt == 1)
-   host-ops-disable(host);
+   if (host-claim_cnt == 1) {
+   if (atomic_read(host-sdio_narrowed) == 1)
+   atomic_set(host-sdio_narrowed, 0);
+   if (host-ops-disable)
+   host-ops-disable(host);
+   }
 
spin_lock_irqsave(host-lock, flags);
if (--host-claim_cnt) {
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 5bc6c7dbbd60..9761e4d5f49b 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -288,7 +288,7 @@ static int sdio_disable_wide(struct mmc_card *card)
 }
 
 
-static int sdio_enable_4bit_bus(struct mmc_card *card)
+int sdio_enable_4bit_bus(struct mmc_card *card)
 {
int err;
 
@@ -313,6 +313,45 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)
return err;
 }
 
+static void mmc_sdio_width_work(struct work_struct *work)
+{
+   struct mmc_host *host = container_of(work, struct mmc_host,
+sdio_width_work);
+   atomic_t noblock;
+
+   atomic_set(noblock, 1);
+   if (__mmc_claim_host(host, noblock))
+   return;
+   if (atomic_read(host-sdio_narrowed) != 1) {
+   /* Nothing to do */
+   mmc_release_host(host);
+   return;
+   }
+   if (sdio_disable_wide(host-card) == 0)
+   atomic_set(host-sdio_narrowed, 2);
+   else
+   atomic_set(host-sdio_narrowed, 0);
+   mmc_release_host(host);
+}
+
+int mmc_sdio_want_no_clocks(struct mmc_host *host)
+{
+   if (!(host-caps  MMC_CAP_SDIO_IRQ

[PATCH 2/4] usb: phy: twl4030: allow charger to see usb current draw limits.

2015-02-23 Thread NeilBrown
The charger needs to know when a USB gadget has been enumerated
and what the agreed maximum current was so that it can adjust
charging accordingly.

So define a set_power() function to record the permitted
draw, and pass a pointer to that when sending USB_EVENT_ENUMERATED
notification.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/phy/phy-twl4030-usb.c |   27 +--
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 97c59074233f..023fe150c7a1 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -163,6 +163,11 @@ struct twl4030_usb {
enum omap_musb_vbus_id_status linkstat;
boolvbus_supplied;
 
+   /* Permitted vbus draw - only meaningful after
+* USB_EVENT_ENUMERATED
+*/
+   unsignedvbus_draw;
+
struct delayed_work id_workaround_work;
 };
 
@@ -547,12 +552,7 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
mutex_unlock(twl-lock);
 
if (status_changed) {
-   /* FIXME add a set_power() method so that B-devices can
-* configure the charger appropriately.  It's not always
-* correct to consume VBUS power, and how much current to
-* consume is a function of the USB configuration chosen
-* by the host.
-*
+   /*
 * REVISIT usb_gadget_vbus_connect(...) as needed, ditto
 * its disconnect() sibling, when changing to/from the
 * USB_LINK_VBUS state.  musb_hdrc won't care until it
@@ -625,6 +625,20 @@ static int twl4030_set_host(struct usb_otg *otg, struct 
usb_bus *host)
return 0;
 }
 
+static int twl4030_set_power(struct usb_phy *phy, unsigned mA)
+{
+   struct twl4030_usb *twl = phy_to_twl(phy);
+
+   if (twl-vbus_draw != mA) {
+   phy-last_event = USB_EVENT_ENUMERATED;
+   twl-vbus_draw = mA;
+   atomic_notifier_call_chain(phy-notifier,
+  USB_EVENT_ENUMERATED,
+  twl-vbus_draw);
+   }
+   return 0;
+}
+
 static const struct phy_ops ops = {
.init   = twl4030_phy_init,
.power_on   = twl4030_phy_power_on,
@@ -675,6 +689,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl-phy.label  = twl4030;
twl-phy.otg= otg;
twl-phy.type   = USB_PHY_TYPE_USB2;
+   twl-phy.set_power  = twl4030_set_power;
 
otg-usb_phy= twl-phy;
otg-set_host   = twl4030_set_host;


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/4] usb: phy: twl4030: make runtime pm more reliable.

2015-02-23 Thread NeilBrown
A construct like:

if (pm_runtime_suspended(twl-dev))
   pm_runtime_get_sync(twl-dev);

is against the spirit of the runtime_pm interface as it
makes the internal refcounting useless.

In this case it is also racy, particularly as 'put_autosuspend'
is use to drop a reference.
When that happens a timer is started and the device is
runtime-suspended after the timeout.
If the above code runs in this window, the device will not be
found to be suspended so no pm_runtime reference is taken.
When the timer expires the device will be suspended, which is
against the intention of the code.

So be more direct is taking and dropping references.
If twl-linkstat is VBUS_VALID or ID_GROUND, then hold a
pm_runtime reference, otherwise don't.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/phy/phy-twl4030-usb.c |   20 +---
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 8e87f54671f3..97c59074233f 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -536,8 +536,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 
mutex_lock(twl-lock);
if (status = 0  status != twl-linkstat) {
+   status_changed =
+   (twl-linkstat == OMAP_MUSB_VBUS_VALID ||
+twl-linkstat == OMAP_MUSB_ID_GROUND)
+   !=
+   (status == OMAP_MUSB_VBUS_VALID ||
+status == OMAP_MUSB_ID_GROUND);
twl-linkstat = status;
-   status_changed = true;
}
mutex_unlock(twl-lock);
 
@@ -555,13 +560,10 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 */
if ((status == OMAP_MUSB_VBUS_VALID) ||
(status == OMAP_MUSB_ID_GROUND)) {
-   if (pm_runtime_suspended(twl-dev))
-   pm_runtime_get_sync(twl-dev);
+   pm_runtime_get_sync(twl-dev);
} else {
-   if (pm_runtime_active(twl-dev)) {
-   pm_runtime_mark_last_busy(twl-dev);
-   pm_runtime_put_autosuspend(twl-dev);
-   }
+   pm_runtime_mark_last_busy(twl-dev);
+   pm_runtime_put_autosuspend(twl-dev);
}
omap_musb_mailbox(status);
}
@@ -768,6 +770,10 @@ static int twl4030_usb_remove(struct platform_device *pdev)
 
/* disable complete OTG block */
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+   if (twl-linkstat == OMAP_MUSB_VBUS_VALID ||
+   twl-linkstat == OMAP_MUSB_ID_GROUND)
+   pm_runtime_put_noidle(twl-dev);
pm_runtime_mark_last_busy(twl-dev);
pm_runtime_put(twl-dev);
 


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/4] usb: phy: twl4030: add support for reading restore on ID pin.

2015-02-23 Thread NeilBrown
The twl4030 phy can measure, with low precision, the
resistance-to-ground of the ID pin.

Add a function to read the value, and export the result
via sysfs.

If the read fails, which it does sometimes, try again in 50msec.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/phy/phy-twl4030-usb.c |   63 +
 1 file changed, 63 insertions(+)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 023fe150c7a1..759950898df9 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -374,6 +374,56 @@ static void twl4030_i2c_access(struct twl4030_usb *twl, 
int on)
}
 }
 
+enum twl4030_id_status {
+   TWL4030_GROUND,
+   TWL4030_102K,
+   TWL4030_200K,
+   TWL4030_440K,
+   TWL4030_FLOATING,
+   TWL4030_ID_UNKNOWN,
+};
+static char *twl4030_id_names[] = {
+   ground,
+   102k,
+   200k,
+   440k,
+   floating,
+   unknown
+};
+
+enum twl4030_id_status twl4030_get_id(struct twl4030_usb *twl)
+{
+   int ret;
+
+   pm_runtime_get_sync(twl-dev);
+   if (twl-usb_mode == T2_USB_MODE_ULPI)
+   twl4030_i2c_access(twl, 1);
+   ret = twl4030_usb_read(twl, ULPI_OTG_CTRL);
+   if (ret  0 || !(ret  ULPI_OTG_ID_PULLUP)) {
+   /* Need pull-up to read ID */
+   twl4030_usb_set_bits(twl, ULPI_OTG_CTRL,
+ULPI_OTG_ID_PULLUP);
+   mdelay(50);
+   }
+   ret = twl4030_usb_read(twl, ID_STATUS);
+   if (ret  0 || (ret  0x1f) == 0) {
+   mdelay(50);
+   ret = twl4030_usb_read(twl, ID_STATUS);
+   }
+
+   if (twl-usb_mode == T2_USB_MODE_ULPI)
+   twl4030_i2c_access(twl, 0);
+   pm_runtime_put_autosuspend(twl-dev);
+
+   if (ret  0)
+   return TWL4030_ID_UNKNOWN;
+   ret = ffs(ret) - 1;
+   if (ret  TWL4030_GROUND || ret  TWL4030_FLOATING)
+   return TWL4030_ID_UNKNOWN;
+
+   return ret;
+}
+
 static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
 {
u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
@@ -531,6 +581,16 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
 }
 static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
 
+static ssize_t twl4030_usb_id_show(struct device *dev,
+  struct device_attribute *attr,
+  char *buf)
+{
+   struct twl4030_usb *twl = dev_get_drvdata(dev);
+   return scnprintf(buf, PAGE_SIZE, %s\n,
+twl4030_id_names[twl4030_get_id(twl)]);
+}
+static DEVICE_ATTR(id, 0444, twl4030_usb_id_show, NULL);
+
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
struct twl4030_usb *twl = _twl;
@@ -723,6 +783,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, twl);
if (device_create_file(pdev-dev, dev_attr_vbus))
dev_warn(pdev-dev, could not create sysfs file\n);
+   if (device_create_file(pdev-dev, dev_attr_id))
+   dev_warn(pdev-dev, could not create sysfs file\n);
 
ATOMIC_INIT_NOTIFIER_HEAD(twl-phy.notifier);
 
@@ -768,6 +830,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
pm_runtime_get_sync(twl-dev);
cancel_delayed_work(twl-id_workaround_work);
device_remove_file(twl-dev, dev_attr_vbus);
+   device_remove_file(twl-dev, dev_attr_id);
 
/* set transceiver mode to power on defaults */
twl4030_usb_set_mode(twl, -1);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/4] usb: phy: twl4030: test ID resistance to see if charger is present.

2015-02-23 Thread NeilBrown
If an 'A' plug is inserted, ID should be pulled to ground.
If a 'B' plug, then ID should be floating.

If an Accessory Charger Adapter is inserted, then ID will
be neither grounded nor floating.  In this case tell the
USB subsystem that it is an A plug, and the battery
charging subsystem that it is a charger.

Fortunately, this will treat the Openmoko charger (and
other similar chargers) as a charger.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/phy/phy-twl4030-usb.c |   28 
 1 file changed, 28 insertions(+)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 759950898df9..8a43080cdbd7 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -596,9 +596,31 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
struct twl4030_usb *twl = _twl;
enum omap_musb_vbus_id_status status;
bool status_changed = false;
+   bool found_charger = false;
 
status = twl4030_usb_linkstat(twl);
 
+   if (status == OMAP_MUSB_ID_GROUND ||
+   status == OMAP_MUSB_VBUS_VALID) {
+   /* We should check the resistance on the ID pin.
+* If not a Ground or Floating, then this is
+* likely a charger
+*/
+   enum twl4030_id_status sts = twl4030_get_id(twl);
+   if (sts  TWL4030_GROUND 
+   sts  TWL4030_FLOATING) {
+   /*
+* This might be a charger, or an
+* Accessory Charger Adapter.
+* In either case we can charge, and it
+* makes sense to tell the USB system
+* that we might be acting as a HOST.
+*/
+   status = OMAP_MUSB_ID_GROUND;
+   found_charger = true;
+   }
+   }
+
mutex_lock(twl-lock);
if (status = 0  status != twl-linkstat) {
status_changed =
@@ -627,6 +649,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
}
omap_musb_mailbox(status);
}
+   if (found_charger  twl-phy.last_event != USB_EVENT_CHARGER) {
+   twl-phy.last_event = USB_EVENT_CHARGER;
+   atomic_notifier_call_chain(twl-phy.notifier,
+  USB_EVENT_CHARGER,
+  NULL);
+   }
 
/* don't schedule during sleep - irq works right then */
if (status == OMAP_MUSB_ID_GROUND  pm_runtime_active(twl-dev)) {


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/4] Enhancements to twl4030 phy to support better charging.

2015-02-23 Thread NeilBrown
Hi,
 the following 4 patches make some improvements to the twl4030
 phy.  Together with some other patches I have for twl4030_charger,
 they allow for better automatic control of charging.

 In particular, the status of the ID pin is assessed and the
 result in communicated to the charger drivers.
 There is also support for conveying the max current negotiated by a
 host to the charger.

Comments most welcome.

thanks,
NeilBrown


---

NeilBrown (4):
  usb: phy: twl4030: make runtime pm more reliable.
  usb: phy: twl4030: allow charger to see usb current draw limits.
  usb: phy: twl4030: add support for reading restore on ID pin.
  usb: phy: twl4030: test ID resistance to see if charger is present.


 drivers/phy/phy-twl4030-usb.c |  138 +
 1 file changed, 125 insertions(+), 13 deletions(-)

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 08/15] twl4030_charger: distinguish between USB current and 'AC' current

2015-02-23 Thread NeilBrown
The twl4030 charger has two current sources, 'USB' and 'AC' (which is
really DC of course...).

If 'AC' is providing current, we should set the current limit
differently to when it isn't (and so USB is used).
So split 'cur' into 'usb_cur' and 'ac_cur' and use accordingly.

Now we must review the current setting on any interrupt or USB
event which might indicate that the charger-source has changed.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   30 +-
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 7c35cd9ba171..bfc9b808301e 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,6 +22,7 @@
 #include linux/power_supply.h
 #include linux/notifier.h
 #include linux/usb/otg.h
+#include linux/i2c/twl4030-madc.h
 
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
@@ -103,7 +104,9 @@ struct twl4030_bci {
/* ichg values in uA. If any are 'large', we set CGAIN to
 * '1' which doubles the range for half the precision.
 */
-   int ichg_eoc, ichg_lo, ichg_hi, cur;
+   int ichg_eoc, ichg_lo, ichg_hi;
+   int usb_cur, ac_cur;
+   boolac_is_active;
 
unsigned long   event;
 };
@@ -224,11 +227,23 @@ static int ua2regval(int ua, bool cgain)
 static int twl4030_charger_update_current(struct twl4030_bci *bci)
 {
int status;
+   int cur;
unsigned reg, cur_reg;
u8 bcictl1, oldreg, fullreg;
int cgain = 0;
u8 boot_bci;
 
+   /* If VAC exceeds 4.5V (MADC 11) and ac is enabled, set current
+* for 'ac'
+*/
+   if (twl4030_get_madc_conversion(11)  4500) {
+   cur = bci-ac_cur;
+   bci-ac_is_active = 1;
+   } else {
+   cur = bci-usb_cur;
+   bci-ac_is_active = 0;
+   }
+
/* First, check thresholds and see if cgain is needed */
if (bci-ichg_eoc = 20)
cgain = 1;
@@ -236,7 +251,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
cgain = 1;
if (bci-ichg_hi = 82)
cgain = 1;
-   if (bci-cur  852000)
+   if (cur  852000)
cgain = 1;
 
status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
@@ -311,7 +326,7 @@ static int twl4030_charger_update_current(struct 
twl4030_bci *bci)
 
/* And finally, set the current.  This is stored in
 * two registers. */
-   reg = ua2regval(bci-cur, cgain);
+   reg = ua2regval(cur, cgain);
/* we have only 10 bit */
if (reg  0x3ff)
reg = 0x3ff;
@@ -364,6 +379,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
 
+   twl4030_charger_update_current(bci);
+
/* Need to keep phy powered */
if (!bci-usb_enabled) {
pm_runtime_get_sync(bci-transceiver-dev);
@@ -456,6 +473,7 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void 
*arg)
struct twl4030_bci *bci = arg;
 
dev_dbg(bci-dev, CHG_PRES irq\n);
+   twl4030_charger_update_current(bci);
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
 
@@ -488,6 +506,7 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
power_supply_changed(bci-ac);
power_supply_changed(bci-usb);
}
+   twl4030_charger_update_current(bci);
 
/* various monitoring events, for now we just log them here */
if (irqs1  (TWL4030_TBATOR2 | TWL4030_TBATOR1))
@@ -701,10 +720,11 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
bci-ichg_eoc = 80100; /* Stop charging when current drops to here */
bci-ichg_lo = 241000; /* low threshold */
bci-ichg_hi = 50; /* High threshold */
+   bci-ac_cur = 50; /* 500mA */
if (allow_usb)
-   bci-cur = 50;  /* 500mA */
+   bci-usb_cur = 50;  /* 500mA */
else
-   bci-cur = 10;  /* 100mA */
+   bci-usb_cur = 10;  /* 100mA */
 
bci-dev = pdev-dev;
bci-irq_chg = platform_get_irq(pdev, 0);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 07/15] twl4030_charger: allow fine control of charger current.

2015-02-23 Thread NeilBrown
The twl4030 allows control of the incoming current.
Part of this control is a 'CGAIN' setting which doubles
the range for half the precision.  This control affects
several different current setting, so all need to be updated
at once when CGAIN is changed.

With this patch, all of these current setting are managed
by the driver, but most are left at their default settings.

The current drawn is set to 500mA if the allow_usb module parameter is
set, and to 100mA otherwise.
More fine control will appear in later patches.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |  161 +--
 1 file changed, 153 insertions(+), 8 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 0b6fb06a0c01..7c35cd9ba171 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -31,6 +31,11 @@
 #define TWL4030_BCIMFSTS4  0x10
 #define TWL4030_BCICTL10x23
 #define TWL4030_BB_CFG 0x12
+#define TWL4030_BCIIREF1   0x27
+#define TWL4030_BCIIREF2   0x28
+#define TWL4030_BCIMFKEY   0x11
+#define TWL4030_BCIMFTH8   0x1d
+#define TWL4030_BCIMFTH9   0x1e
 
 #define TWL4030_BCIMFSTS1  0x01
 
@@ -95,6 +100,11 @@ struct twl4030_bci {
int irq_bci;
int usb_enabled;
 
+   /* ichg values in uA. If any are 'large', we set CGAIN to
+* '1' which doubles the range for half the precision.
+*/
+   int ichg_eoc, ichg_lo, ichg_hi, cur;
+
unsigned long   event;
 };
 
@@ -211,6 +221,140 @@ static int ua2regval(int ua, bool cgain)
return ret;
 }
 
+static int twl4030_charger_update_current(struct twl4030_bci *bci)
+{
+   int status;
+   unsigned reg, cur_reg;
+   u8 bcictl1, oldreg, fullreg;
+   int cgain = 0;
+   u8 boot_bci;
+
+   /* First, check thresholds and see if cgain is needed */
+   if (bci-ichg_eoc = 20)
+   cgain = 1;
+   if (bci-ichg_lo = 40)
+   cgain = 1;
+   if (bci-ichg_hi = 82)
+   cgain = 1;
+   if (bci-cur  852000)
+   cgain = 1;
+
+   status = twl4030_bci_read(TWL4030_BCICTL1, bcictl1);
+   if (status  0)
+   return status;
+   if (twl_i2c_read_u8(TWL_MODULE_PM_MASTER, boot_bci,
+   TWL4030_PM_MASTER_BOOT_BCI)  0)
+   boot_bci = 0;
+   boot_bci = 7;
+
+   if ((!!cgain) != !!(bcictl1  TWL4030_CGAIN))
+   /* Need to turn for charging while we change the
+* CGAIN bit.  Leave it off while everything is
+* updated.
+*/
+   twl4030_clear_set_boot_bci(boot_bci, 0);
+
+   /* For ichg_eoc, reg value must be 100000, we only
+* set the  in high nibble.
+*/
+   reg = ua2regval(bci-ichg_eoc, cgain);
+   if (reg  0x278)
+   reg = 0x278;
+   if (reg  0x200)
+   reg = 0x200;
+   reg = (reg  3)  0xf;
+   fullreg = reg  4;
+
+   /* For ichg_lo, reg value must be 10.
+*  is stored in low nibble */
+   reg = ua2regval(bci-ichg_lo, cgain);
+   if (reg  0x2F0)
+   reg = 0x2F0;
+   if (reg  0x200)
+   reg = 0x200;
+   reg = (reg  4)  0xf;
+   fullreg |= reg;
+
+   /* ichg_eoc and ichg_lo live in same register */
+   status = twl4030_bci_read(TWL4030_BCIMFTH8, oldreg);
+   if (status  0)
+   return status;
+   if (oldreg != fullreg) {
+   status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xF4,
+ TWL4030_BCIMFKEY);
+   if (status  0)
+   return status;
+   twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+fullreg, TWL4030_BCIMFTH8);
+   }
+
+   /* ichg_hi threshold must be 101100 (I think) */
+   reg = ua2regval(bci-ichg_hi, cgain);
+   if (reg  0x3E0)
+   reg = 0x3E0;
+   if (reg  0x200)
+   reg = 0x200;
+   fullreg = (reg  5)  0xF;
+   fullreg = 4;
+   status = twl4030_bci_read(TWL4030_BCIMFTH9, oldreg);
+   if (status  0)
+   return status;
+   if ((oldreg  0xF0) != fullreg) {
+   fullreg |= (oldreg  0x0F);
+   status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7,
+ TWL4030_BCIMFKEY);
+   if (status  0)
+   return status;
+   twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+fullreg, TWL4030_BCIMFTH9);
+   }
+
+   /* And finally, set the current.  This is stored in
+* two registers. */
+   reg = ua2regval(bci-cur, cgain);
+   /* we have only 10 bit */
+   if (reg  0x3ff)
+   reg = 0x3ff

[PATCH 04/15] twl4030_charger: use runtime_pm to keep usb phy active while charging.

2015-02-23 Thread NeilBrown
The twl4030 usb phy needs to be active while we are using
the USB VBUS as a current source for charging.
In particular, the usb3v1 regulator must be enabled and the
PHY_PWR_PHYPWD bit must be set to keep the phy powered.

commit ab37813f4093a5f59cb8e083cde277289dc72ed3
twl4030_charger: Allow charger to control the regulator that feeds it

Gave the charger control over the regulator, but didn't resolve
the PHY_PWR_PHYPWD issue.

Now that both of these are controlled by runtime_pm in
phy-twl4030-usb, we can simply take a runtime_pm reference to the USB
phy whenever the charger wants to use it as a current source.

So this patch reverts the above commit, and adds the necessary
runtime_pm calls.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/mfd/twl-core.c  |9 -
 drivers/power/twl4030_charger.c |   18 +-
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 489674a2497e..831696ee2472 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -788,9 +788,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
static struct regulator_consumer_supply usb1v8 = {
.supply =   usb1v8,
};
-   static struct regulator_consumer_supply usb3v1[] = {
-   { .supply = usb3v1 },
-   { .supply = bci3v1 },
+   static struct regulator_consumer_supply usb3v1 = {
+   .supply =   usb3v1,
};
 
/* First add the regulators so that they can be used by transceiver */
@@ -818,7 +817,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
return PTR_ERR(child);
 
child = add_regulator_linked(TWL4030_REG_VUSB3V1,
- usb_fixed, usb3v1, 2,
+ usb_fixed, usb3v1, 1,
  features);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -838,7 +837,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned 
irq_base,
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)  child) {
usb1v5.dev_name = dev_name(child);
usb1v8.dev_name = dev_name(child);
-   usb3v1[0].dev_name = dev_name(child);
+   usb3v1.dev_name = dev_name(child);
}
}
 
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 51321f0c5548..11f352a5ef55 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -22,7 +22,6 @@
 #include linux/power_supply.h
 #include linux/notifier.h
 #include linux/usb/otg.h
-#include linux/regulator/machine.h
 
 #define TWL4030_BCIMSTATEC 0x02
 #define TWL4030_BCIICHG0x08
@@ -94,7 +93,6 @@ struct twl4030_bci {
struct work_struct  work;
int irq_chg;
int irq_bci;
-   struct regulator*usb_reg;
int usb_enabled;
 
unsigned long   event;
@@ -208,7 +206,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
 {
int ret;
 
-   if (enable) {
+   if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
/* Check for USB charger connected */
if (!twl4030_bci_have_vbus(bci))
return -ENODEV;
@@ -222,14 +220,9 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
return -EACCES;
}
 
-   /* Need to keep regulator on */
+   /* Need to keep phy powered */
if (!bci-usb_enabled) {
-   ret = regulator_enable(bci-usb_reg);
-   if (ret) {
-   dev_err(bci-dev,
-   Failed to enable regulator\n);
-   return ret;
-   }
+   pm_runtime_get_sync(bci-transceiver-dev);
bci-usb_enabled = 1;
}
 
@@ -244,7 +237,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
} else {
ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
if (bci-usb_enabled) {
-   regulator_disable(bci-usb_reg);
+   pm_runtime_mark_last_busy(bci-transceiver-dev);
+   pm_runtime_put_autosuspend(bci-transceiver-dev);
bci-usb_enabled = 0;
}
}
@@ -602,8 +596,6 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
bci

[PATCH 06/15] twl4030_charger: split uA calculation into a function.

2015-02-23 Thread NeilBrown
We will need this calculation in other places, so
create functions to map between register value and uA value.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   48 ---
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index db8931a17541..0b6fb06a0c01 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -178,6 +178,40 @@ static int twl4030_is_battery_present(struct twl4030_bci 
*bci)
 }
 
 /*
+ * TI provided formulas:
+ * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
+ * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
+ * Here we use integer approximation of:
+ * CGAIN == 0: val * 1.6618 - 0.85 * 1000
+ * CGAIN == 1: (val * 1.6618 - 0.85 * 1000) * 2
+ */
+/*
+ * convert twl register value for currents into uA
+ */
+static int regval2ua(int regval, bool cgain)
+{
+   if (cgain)
+   return (regval * 16618 - 8500 * 1000) / 5;
+   else
+   return (regval * 16618 - 8500 * 1000) / 10;
+}
+
+/*
+ * convert uA currents into twl register value
+ */
+static int ua2regval(int ua, bool cgain)
+{
+   int ret;
+   if (cgain)
+   ua /= 2;
+   ret = (ua * 10 + 8500 * 1000) / 16618;
+   /* rounding problems */
+   if (ret  512)
+   ret = 512;
+   return ret;
+}
+
+/*
  * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
@@ -366,14 +400,6 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, 
unsigned long val,
return NOTIFY_OK;
 }
 
-/*
- * TI provided formulas:
- * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
- * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
- * Here we use integer approximation of:
- * CGAIN == 0: val * 1.6618 - 0.85
- * CGAIN == 1: (val * 1.6618 - 0.85) * 2
- */
 static int twl4030_charger_get_current(void)
 {
int curr;
@@ -388,11 +414,7 @@ static int twl4030_charger_get_current(void)
if (ret)
return ret;
 
-   ret = (curr * 16618 - 850 * 1) / 10;
-   if (bcictl1  TWL4030_CGAIN)
-   ret *= 2;
-
-   return ret;
+   return regval2ua(curr, bcictl1  TWL4030_CGAIN);
 }
 
 /*


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 05/15] twl4030_charger: trust phy to determine when USB power is available.

2015-02-23 Thread NeilBrown
The usb phy driver already determines when VBUS is available,
so repeating the test in the charger driver is pointless duplication.

On probe, process the last event from the phy, and from then on,
do whatever the phy tells us without double-checking.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   33 ++---
 1 file changed, 6 insertions(+), 27 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 11f352a5ef55..db8931a17541 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -178,28 +178,6 @@ static int twl4030_is_battery_present(struct twl4030_bci 
*bci)
 }
 
 /*
- * Check if VBUS power is present
- */
-static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
-{
-   int ret;
-   u8 hwsts;
-
-   ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, hwsts,
- TWL4030_PM_MASTER_STS_HW_CONDITIONS);
-   if (ret  0)
-   return 0;
-
-   dev_dbg(bci-dev, check_vbus: HW_CONDITIONS %02x\n, hwsts);
-
-   /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */
-   if ((hwsts  TWL4030_STS_VBUS)  !(hwsts  TWL4030_STS_USB_ID))
-   return 1;
-
-   return 0;
-}
-
-/*
  * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
@@ -207,10 +185,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci 
*bci, bool enable)
int ret;
 
if (enable  !IS_ERR_OR_NULL(bci-transceiver)) {
-   /* Check for USB charger connected */
-   if (!twl4030_bci_have_vbus(bci))
-   return -ENODEV;
-
/*
 * Until we can find out what current the device can provide,
 * require a module param to enable USB charging.
@@ -649,7 +623,12 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
dev_warn(pdev-dev, failed to unmask interrupts: %d\n, ret);
 
twl4030_charger_enable_ac(true);
-   twl4030_charger_enable_usb(bci, true);
+   if (!IS_ERR_OR_NULL(bci-transceiver))
+   twl4030_bci_usb_ncb(bci-usb_nb,
+   bci-transceiver-last_event,
+   NULL);
+   else
+   twl4030_charger_enable_usb(bci, false);
if (pdata)
twl4030_charger_enable_backup(pdata-bb_uvolt,
  pdata-bb_uamp);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 00/15] Enhance twl4030_charger functionality.

2015-02-23 Thread NeilBrown
These patches make a number of improvements to twl4030_charger.

So are just internal cleanups (e.g. use of devres).  Others allow
better control of charging through both manual and automatic means.

- the maximum current can be configured via sysfs.
- the charger will only draw that current if it can do so without
  the voltage dropping too much
- a 'continuous' mode is available which ignores voltage and just
  takes what it can (to be used with caution, but very useful in
  some circumstances).
- 'ac' and 'usb' power sources can be configured separately.

Some of this functionality requires patch to phy-twl4030-usb.c which
have been sent separately.

Thanks,
NeilBrown


---

NeilBrown (15):
  power_supply core: support use of devres to register/unregister a power 
supply.
  twl4030_charger: use devm_request_threaded_irq
  twl4030_charger: use devres for power_supply_register and kzalloc.
  twl4030_charger: use runtime_pm to keep usb phy active while charging.
  twl4030_charger: trust phy to determine when USB power is available.
  twl4030_charger: split uA calculation into a function.
  twl4030_charger: allow fine control of charger current.
  twl4030_charger: distinguish between USB current and 'AC' current
  twl4030_charger: allow max_current to be managed via sysfs.
  twl4030_charger: only draw USB current as negotiated with host.
  twl4030_charger: enable manual enable/disable of usb charging.
  twl4030_charger: add software controlled linear charging mode.
  twl4030_charger: add ac/mode to match usb/mode
  twl4030_charger: Increase current carefully while watching voltage.
  twl4030_charger: assume a 'charger' can supply maximum current.


 drivers/mfd/twl-core.c|9 -
 drivers/power/power_supply_core.c |   45 +++
 drivers/power/twl4030_charger.c   |  572 +++--
 include/linux/power_supply.h  |4 
 4 files changed, 539 insertions(+), 91 deletions(-)

--
Signature

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 03/15] twl4030_charger: use devres for power_supply_register and kzalloc.

2015-02-23 Thread NeilBrown
Final allocations/registrations are now managed by devres.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   23 ++-
 1 file changed, 6 insertions(+), 17 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 300dd7a34e80..51321f0c5548 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -565,7 +565,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
int ret;
u32 reg;
 
-   bci = kzalloc(sizeof(*bci), GFP_KERNEL);
+   bci = devm_kzalloc(pdev-dev, sizeof(*bci), GFP_KERNEL);
if (bci == NULL)
return -ENOMEM;
 
@@ -580,7 +580,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
ret = twl4030_is_battery_present(bci);
if  (ret) {
dev_crit(pdev-dev, Battery was not detected:%d\n, ret);
-   goto fail_no_battery;
+   goto fail;
}
 
platform_set_drvdata(pdev, bci);
@@ -590,10 +590,10 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
bci-ac.num_properties = ARRAY_SIZE(twl4030_charger_props);
bci-ac.get_property = twl4030_bci_get_property;
 
-   ret = power_supply_register(pdev-dev, bci-ac);
+   ret = devm_power_supply_register(pdev-dev, bci-ac);
if (ret) {
dev_err(pdev-dev, failed to register ac: %d\n, ret);
-   goto fail_register_ac;
+   goto fail;
}
 
bci-usb.name = twl4030_usb;
@@ -604,10 +604,10 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
 
bci-usb_reg = regulator_get(bci-dev, bci3v1);
 
-   ret = power_supply_register(pdev-dev, bci-usb);
+   ret = devm_power_supply_register(pdev-dev, bci-usb);
if (ret) {
dev_err(pdev-dev, failed to register usb: %d\n, ret);
-   goto fail_register_usb;
+   goto fail;
}
 
ret = devm_request_threaded_irq(pdev-dev, bci-irq_chg, NULL,
@@ -667,13 +667,6 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
return 0;
 
 fail:
-   power_supply_unregister(bci-usb);
-fail_register_usb:
-   power_supply_unregister(bci-ac);
-fail_register_ac:
-fail_no_battery:
-   kfree(bci);
-
return ret;
 }
 
@@ -691,10 +684,6 @@ static int __exit twl4030_bci_remove(struct 
platform_device *pdev)
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR2A);
 
-   power_supply_unregister(bci-usb);
-   power_supply_unregister(bci-ac);
-   kfree(bci);
-
return 0;
 }
 


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 02/15] twl4030_charger: use devm_request_threaded_irq

2015-02-23 Thread NeilBrown
This simplifies the error paths.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/twl4030_charger.c |   18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 4cf5ffbc904a..300dd7a34e80 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -610,21 +610,21 @@ static int __init twl4030_bci_probe(struct 
platform_device *pdev)
goto fail_register_usb;
}
 
-   ret = request_threaded_irq(bci-irq_chg, NULL,
+   ret = devm_request_threaded_irq(pdev-dev, bci-irq_chg, NULL,
twl4030_charger_interrupt, IRQF_ONESHOT, pdev-name,
bci);
if (ret  0) {
dev_err(pdev-dev, could not request irq %d, status %d\n,
bci-irq_chg, ret);
-   goto fail_chg_irq;
+   goto fail;
}
 
-   ret = request_threaded_irq(bci-irq_bci, NULL,
+   ret = devm_request_threaded_irq(pdev-dev, bci-irq_bci, NULL,
twl4030_bci_interrupt, IRQF_ONESHOT, pdev-name, bci);
if (ret  0) {
dev_err(pdev-dev, could not request irq %d, status %d\n,
bci-irq_bci, ret);
-   goto fail_bci_irq;
+   goto fail;
}
 
INIT_WORK(bci-work, twl4030_bci_usb_work);
@@ -647,7 +647,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
   TWL4030_INTERRUPTS_BCIIMR1A);
if (ret  0) {
dev_err(pdev-dev, failed to unmask interrupts: %d\n, ret);
-   goto fail_unmask_interrupts;
+   goto fail;
}
 
reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
@@ -666,11 +666,7 @@ static int __init twl4030_bci_probe(struct platform_device 
*pdev)
 
return 0;
 
-fail_unmask_interrupts:
-   free_irq(bci-irq_bci, bci);
-fail_bci_irq:
-   free_irq(bci-irq_chg, bci);
-fail_chg_irq:
+fail:
power_supply_unregister(bci-usb);
 fail_register_usb:
power_supply_unregister(bci-ac);
@@ -695,8 +691,6 @@ static int __exit twl4030_bci_remove(struct platform_device 
*pdev)
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 TWL4030_INTERRUPTS_BCIIMR2A);
 
-   free_irq(bci-irq_bci, bci);
-   free_irq(bci-irq_chg, bci);
power_supply_unregister(bci-usb);
power_supply_unregister(bci-ac);
kfree(bci);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/15] power_supply core: support use of devres to register/unregister a power supply.

2015-02-23 Thread NeilBrown
Using devm_power_supply_register allows the unregister to happen
automatically on error or final put.

Signed-off-by: NeilBrown ne...@suse.de
---
 drivers/power/power_supply_core.c |   45 +
 include/linux/power_supply.h  |4 +++
 2 files changed, 49 insertions(+)

diff --git a/drivers/power/power_supply_core.c 
b/drivers/power/power_supply_core.c
index 694e8cddd5c1..44c810456212 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -617,6 +617,51 @@ int power_supply_register_no_ws(struct device *parent, 
struct power_supply *psy)
 }
 EXPORT_SYMBOL_GPL(power_supply_register_no_ws);
 
+static void devm_power_supply_release(struct device *dev, void *res)
+{
+   struct power_supply **psy = res;
+
+   power_supply_unregister(*psy);
+}
+
+int devm_power_supply_register(struct device *parent, struct power_supply *psy)
+{
+   struct power_supply **ptr = devres_alloc(devm_power_supply_release,
+sizeof(*ptr), GFP_KERNEL);
+   int ret;
+
+   if (!ptr)
+   return -ENOMEM;
+   ret = __power_supply_register(parent, psy, true);
+   if (ret  0)
+   devres_free(ptr);
+   else {
+   *ptr = psy;
+   devres_add(parent, ptr);
+   }
+   return ret;
+}
+EXPORT_SYMBOL_GPL(devm_power_supply_register);
+
+int devm_power_supply_register_no_ws(struct device *parent, struct 
power_supply *psy)
+{
+   struct power_supply **ptr = devres_alloc(devm_power_supply_release,
+sizeof(*ptr), GFP_KERNEL);
+   int ret;
+
+   if (!ptr)
+   return -ENOMEM;
+   ret = __power_supply_register(parent, psy, false);
+   if (ret  0)
+   devres_free(ptr);
+   else {
+   *ptr = psy;
+   devres_add(parent, ptr);
+   }
+   return ret;
+}
+EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws);
+
 void power_supply_unregister(struct power_supply *psy)
 {
cancel_work_sync(psy-changed_work);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 096dbced02ac..f606d6b4bd56 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -278,6 +278,10 @@ extern int power_supply_register(struct device *parent,
 struct power_supply *psy);
 extern int power_supply_register_no_ws(struct device *parent,
 struct power_supply *psy);
+extern int devm_power_supply_register(struct device *parent,
+struct power_supply *psy);
+extern int devm_power_supply_register_no_ws(struct device *parent,
+struct power_supply *psy);
 extern void power_supply_unregister(struct power_supply *psy);
 extern int power_supply_powers(struct power_supply *psy, struct device *dev);
 


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/4] mmc: core: allow non-blocking form of mmc_claim_host

2015-01-30 Thread NeilBrown
Change the handling for the 'abort' flag so that if
it is set, but we can claim the host, then do the claim,
rather than aborting.

When the abort is async this just means that a race between aborting
an allowing a claim is resolved slightly differently.  Any
code must already be able to handle 'abort' being set just as the host
is claimed.

This allows extra functionality.  If __mmc_claim_host() is called
with an 'abort' pointer which is initialized to '1', it will effect a
non-blocking 'claim'.

Signed-off-by: NeilBrown n...@brown.name
---
 drivers/mmc/core/core.c |3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index e9eb721e3664..051198073d21 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -912,10 +912,11 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t 
*abort)
spin_lock_irqsave(host-lock, flags);
}
set_current_state(TASK_RUNNING);
-   if (!stop) {
+   if (!host-claimed || host-claimer == current) {
host-claimed = 1;
host-claimer = current;
host-claim_cnt += 1;
+   stop = 0;
} else
wake_up(host-wq);
spin_unlock_irqrestore(host-lock, flags);


--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


  1   2   3   >