Re: [PATCH v2 2/2] dts: r40: add second ethernet support

2021-03-08 Thread Evgeny Boger

3/9/21 4:21 AM, Evgeny Boger пишет:

R40 (aka V40, A40i, T3) has two different Ethernet IP
called EMAC and GMAC.
EMAC only support 10/100 Mbit in MII mode,
while GMAC support both 10/100 (MII) and 10/100/1000 (RGMII).

In contrast to A10/A20 where GMAC and EMAC share the same pins
making EMAC somewhat pointless, on R40 EMAC can be routed to port H.
Both EMAC (on port H) and GMAC (on port A)
  can be then enabled at the same time, allowing for two ethernet ports.

Signed-off-by: Evgeny Boger 
---
  arch/arm/boot/dts/sun8i-r40.dtsi | 59 
  1 file changed, 59 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index d5ad3b9efd12..c31386e421b1 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -217,6 +217,20 @@
#size-cells = <1>;
ranges;
  
+			sram_a: sram@0 {

+   compatible = "mmio-sram";
+   reg = <0x 0xc000>;
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges = <0 0x 0xc000>;
+
+   emac_sram: sram-section@8000 {
+   compatible = 
"allwinner,sun4i-a10-sram-a3-a4";
+   reg = <0x8000 0x4000>;
+   status = "okay";
+   };
+   };
+
sram_c: sram@1d0 {
compatible = "mmio-sram";
reg = <0x01d0 0xd>;
@@ -541,6 +555,33 @@
drive-strength = <40>;
};
  
+			emac_pa_pins: emac-pa-pins {

+   pins = "PA0", "PA1", "PA2",
+  "PA3", "PA4", "PA5", "PA6",
+  "PA7", "PA8", "PA9", "PA10",
+  "PA11", "PA12", "PA13", "PA14",
+  "PA15", "PA16";
+   function = "emac";
+   };
+
+   emac_ph_pins: emac-ph-pins {
+   pins = "PH8", "PH9", "PH10", "PH11",
+  "PH14", "PH15", "PH16", "PH17",
+  "PH18","PH19", "PH20", "PH21",
+  "PH22", "PH23", "PH24", "PH25",
+  "PH26", "PH27";
+   function = "emac";
+   };
+
+   emac_pa_pins: emac-pa-pins {
+   pins = "PA0", "PA1", "PA2",
+  "PA3", "PA4", "PA5", "PA6",
+  "PA7", "PA8", "PA9", "PA10",
+  "PA11", "PA12", "PA13", "PA14",
+  "PA15", "PA16";
+   function = "emac";
+   };
+


oh. a duplicate node name. I guess I've just got used to editing *after* 
submitting the pull request on github.


Sorry for the mess, will fix in v3.



i2c0_pins: i2c0-pins {
pins = "PB0", "PB1";
function = "i2c0";
@@ -885,6 +926,24 @@
};
};
  
+		emac: ethernet@1c0b000 {

+   compatible = "allwinner,sun4i-r40-emac";
+   reg = <0x01c0b000 0x1000>;
+   interrupts = ;
+   clocks = < CLK_BUS_EMAC>;
+   resets = < RST_BUS_EMAC>;
+   allwinner,sram = <_sram 1>;
+   status = "disabled";
+   };
+
+   emac_mdio: mdio@1c0b080 {
+   compatible = "allwinner,sun4i-a10-mdio";
+   reg = <0x01c0b080 0x14>;
+   status = "disabled";
+   #address-cells = <1>;
+   #size-cells = <0>;
+   };
+
mbus: dram-controller@1c62000 {
compatible = "allwinner,sun8i-r40-mbus";
reg = <0x01c62000 0x1000>;




[PATCH v2 2/2] dts: r40: add second ethernet support

2021-03-08 Thread Evgeny Boger
R40 (aka V40, A40i, T3) has two different Ethernet IP
called EMAC and GMAC.
EMAC only support 10/100 Mbit in MII mode,
while GMAC support both 10/100 (MII) and 10/100/1000 (RGMII).

In contrast to A10/A20 where GMAC and EMAC share the same pins
making EMAC somewhat pointless, on R40 EMAC can be routed to port H.
Both EMAC (on port H) and GMAC (on port A)
 can be then enabled at the same time, allowing for two ethernet ports.

Signed-off-by: Evgeny Boger 
---
 arch/arm/boot/dts/sun8i-r40.dtsi | 59 
 1 file changed, 59 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index d5ad3b9efd12..c31386e421b1 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -217,6 +217,20 @@
#size-cells = <1>;
ranges;
 
+   sram_a: sram@0 {
+   compatible = "mmio-sram";
+   reg = <0x 0xc000>;
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges = <0 0x 0xc000>;
+
+   emac_sram: sram-section@8000 {
+   compatible = 
"allwinner,sun4i-a10-sram-a3-a4";
+   reg = <0x8000 0x4000>;
+   status = "okay";
+   };
+   };
+
sram_c: sram@1d0 {
compatible = "mmio-sram";
reg = <0x01d0 0xd>;
@@ -541,6 +555,33 @@
drive-strength = <40>;
};
 
+   emac_pa_pins: emac-pa-pins {
+   pins = "PA0", "PA1", "PA2",
+  "PA3", "PA4", "PA5", "PA6",
+  "PA7", "PA8", "PA9", "PA10",
+  "PA11", "PA12", "PA13", "PA14",
+  "PA15", "PA16";
+   function = "emac";
+   };
+
+   emac_ph_pins: emac-ph-pins {
+   pins = "PH8", "PH9", "PH10", "PH11",
+  "PH14", "PH15", "PH16", "PH17",
+  "PH18","PH19", "PH20", "PH21",
+  "PH22", "PH23", "PH24", "PH25",
+  "PH26", "PH27";
+   function = "emac";
+   };
+
+   emac_pa_pins: emac-pa-pins {
+   pins = "PA0", "PA1", "PA2",
+  "PA3", "PA4", "PA5", "PA6",
+  "PA7", "PA8", "PA9", "PA10",
+  "PA11", "PA12", "PA13", "PA14",
+  "PA15", "PA16";
+   function = "emac";
+   };
+
i2c0_pins: i2c0-pins {
pins = "PB0", "PB1";
function = "i2c0";
@@ -885,6 +926,24 @@
};
};
 
+   emac: ethernet@1c0b000 {
+   compatible = "allwinner,sun4i-r40-emac";
+   reg = <0x01c0b000 0x1000>;
+   interrupts = ;
+   clocks = < CLK_BUS_EMAC>;
+   resets = < RST_BUS_EMAC>;
+   allwinner,sram = <_sram 1>;
+   status = "disabled";
+   };
+
+   emac_mdio: mdio@1c0b080 {
+   compatible = "allwinner,sun4i-a10-mdio";
+   reg = <0x01c0b080 0x14>;
+   status = "disabled";
+   #address-cells = <1>;
+   #size-cells = <0>;
+   };
+
mbus: dram-controller@1c62000 {
compatible = "allwinner,sun8i-r40-mbus";
reg = <0x01c62000 0x1000>;
-- 
2.17.1



[PATCH v2 0/2] sun8i: r40: second ethernet support

2021-03-08 Thread Evgeny Boger
This patch series adds support for two Ethernet ports on Allwinner R40.

R40 (aka V40,A40i,T3) has two different Ethernet IPs called EMAC and GMAC.
EMAC only support 10/100 Mbit in MII mode, while GMAC support both 10/100
(MII) and 10/100/1000 (RGMII).

In contrast to A10/A20 where GMAC and EMAC share the same pins making EMAC
somewhat pointless, on R40 EMAC can be routed to port H.
Both EMAC (on port H) and GMAC (on port A) can be then enabled at the same 
time, allowing for two ethernet ports.

Tested on custom A40i board with two IP101GRI PHYs in MII mode.

Changes in v2:
 - EMAC reset is no longer optional on R40
 - Add a new DT compatible string for R40 EMAC
 - Deassert reset line before enabling the clock
 - minor fixes: formatting, DT node order, leftover pinctrl props


Evgeny Boger (2):
  net: allwinner: reset control support
  dts: r40: add second ethernet support

 .../net/allwinner,sun4i-a10-emac.yaml | 11 +++-
 arch/arm/boot/dts/sun8i-r40.dtsi  | 59 +
 drivers/net/ethernet/allwinner/sun4i-emac.c   | 65 +--
 3 files changed, 129 insertions(+), 6 deletions(-)

-- 
2.17.1



[PATCH v2 1/2] net: allwinner: reset control support

2021-03-08 Thread Evgeny Boger
R40 (aka V40/A40i/T3) and A10/A20 share the same EMAC IP.
However, on R40 the EMAC is gated by default.

Signed-off-by: Evgeny Boger 
---
 .../net/allwinner,sun4i-a10-emac.yaml | 11 +++-
 drivers/net/ethernet/allwinner/sun4i-emac.c   | 65 +--
 2 files changed, 70 insertions(+), 6 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml 
b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml
index 8d8560a67abf..27f99372d153 100644
--- a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml
+++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml
@@ -15,7 +15,12 @@ maintainers:
 
 properties:
   compatible:
-const: allwinner,sun4i-a10-emac
+oneOf:
+  - const: allwinner,sun4i-a10-emac
+  - const: allwinner,sun4i-r40-emac
+  - items:
+  - const: allwinner,sun4i-r40-emac
+  - const: allwinner,sun4i-a10-emac
 
   reg:
 maxItems: 1
@@ -30,6 +35,9 @@ properties:
 description: Phandle to the device SRAM
 $ref: /schemas/types.yaml#/definitions/phandle-array
 
+  resets:
+maxItems: 1
+
 required:
   - compatible
   - reg
@@ -47,6 +55,7 @@ examples:
 reg = <0x01c0b000 0x1000>;
 interrupts = <55>;
 clocks = <_gates 17>;
+resets = < RST_BUS_EMAC>;
 phy-handle = <>;
 allwinner,sram = <_sram 1>;
 };
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c 
b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 5ed80d9a6b9f..b26913610a38 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "sun4i-emac.h"
@@ -68,6 +69,15 @@ MODULE_PARM_DESC(watchdog, "transmit timeout in 
milliseconds");
  * devices, EMACA and EMACB.
  */
 
+/**
+ * struct emac_quirks - Differences between SoC variants.
+ *
+ * @has_reset: SoC needs reset deasserted.
+ */
+struct emac_quirks {
+   boolhas_reset;
+};
+
 struct emac_board_info {
struct clk  *clk;
struct device   *dev;
@@ -85,6 +95,7 @@ struct emac_board_info {
unsigned intlink;
unsigned intspeed;
unsigned intduplex;
+   struct reset_control*reset;
 
phy_interface_t phy_interface;
 };
@@ -791,6 +802,7 @@ static int emac_probe(struct platform_device *pdev)
struct net_device *ndev;
int ret = 0;
const char *mac_addr;
+   const struct emac_quirks *quirks;
 
ndev = alloc_etherdev(sizeof(struct emac_board_info));
if (!ndev) {
@@ -809,6 +821,13 @@ static int emac_probe(struct platform_device *pdev)
 
spin_lock_init(>lock);
 
+   quirks = of_device_get_match_data(>dev);
+   if (!quirks) {
+   dev_err(>dev, "Failed to determine the quirks to use\n");
+   ret = -ENODEV;
+   goto out;
+   }
+
db->membase = of_iomap(np, 0);
if (!db->membase) {
dev_err(>dev, "failed to remap registers\n");
@@ -825,16 +844,31 @@ static int emac_probe(struct platform_device *pdev)
goto out_iounmap;
}
 
+   if (quirks->has_reset) {
+   db->reset = devm_reset_control_get_exclusive(>dev, NULL);
+   if (IS_ERR(db->reset)) {
+   dev_err(>dev, "unable to request reset\n");
+   ret = PTR_ERR(db->reset);
+   goto out_dispose_mapping;
+   }
+
+   ret = reset_control_deassert(db->reset);
+   if (ret) {
+   dev_err(>dev, "could not deassert EMAC reset\n");
+   goto out_dispose_mapping;
+   }
+   }
+
db->clk = devm_clk_get(>dev, NULL);
if (IS_ERR(db->clk)) {
ret = PTR_ERR(db->clk);
-   goto out_dispose_mapping;
+   goto out_assert_reset;
}
 
ret = clk_prepare_enable(db->clk);
if (ret) {
dev_err(>dev, "Error couldn't enable clock (%d)\n", ret);
-   goto out_dispose_mapping;
+   goto out_assert_reset;
}
 
ret = sunxi_sram_claim(>dev);
@@ -852,6 +886,7 @@ static int emac_probe(struct platform_device *pdev)
goto out_release_sram;
}
 
+
/* Read MAC-address from DT */
mac_addr = of_get_mac_address(np);
if (!IS_ERR(mac_addr))
@@ -893,6 +928,8 @@ static int emac_probe(struct platform_device *pdev)
sunxi_sram_release(>dev);
 out_clk_disable_unprepare:
clk_disable_unprepare(db->clk);
+out_assert_reset:
+   reset_control_assert(db->reset);
 

Re: [PATCH 1/2] net: allwinner: reset control support

2021-03-08 Thread Evgeny Boger

Hi, thank you for your review!


3/8/21 4:36 PM, Maxime Ripard пишет:

Hi,

On Sun, Mar 07, 2021 at 06:13:51AM +0300, Evgeny Boger wrote:

R40 (aka V40/A40i/T3) and A10/A20 share the same EMAC IP.
However, on R40 the EMAC is gated by default.

Signed-off-by: Evgeny Boger 

On which device was it tested?

It's custom-made Allwinner A40i device with two IP101GRI PHYs in MII mode.

---
  drivers/net/ethernet/allwinner/sun4i-emac.c | 21 -
  1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c 
b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 5ed80d9a6b9f..c0ae06dd922c 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -28,6 +28,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  
  #include "sun4i-emac.h"

@@ -85,6 +86,7 @@ struct emac_board_info {
unsigned intlink;
unsigned intspeed;
unsigned intduplex;
+   struct reset_control *reset;

You should align this with the rest of the other fields




  
  	phy_interface_t		phy_interface;

  };
@@ -791,6 +793,7 @@ static int emac_probe(struct platform_device *pdev)
struct net_device *ndev;
int ret = 0;
const char *mac_addr;
+   struct reset_control *reset;
  
  	ndev = alloc_etherdev(sizeof(struct emac_board_info));

if (!ndev) {
@@ -852,6 +855,19 @@ static int emac_probe(struct platform_device *pdev)
goto out_release_sram;
}
  
+	reset = devm_reset_control_get_optional_exclusive(>dev, NULL);

+   if (IS_ERR(reset)) {
+   dev_err(>dev, "unable to request reset\n");
+   ret = -ENODEV;
+   goto out_release_sram;
+   }

Judging from your commit log, it's not really optional for the R40. The
way we usually deal with this is to have a structure associated with a
new compatible and have a flag tell if that compatible requires a reset
line or not.

The dt binding should also be amended to allow the reset property


got it

+   db->reset = reset;
+   ret = reset_control_deassert(db->reset);
+   if (ret) {
+   dev_err(>dev, "could not deassert EMAC reset\n");
+   goto out_release_sram;
+   }
+

The programming guidelines in the datasheet ask that the reset line must
be deasserted before the clock in enabled.

right, found it at section 3.3.2.6, thanks


Maxime


[PATCH 1/2] net: allwinner: reset control support

2021-03-06 Thread Evgeny Boger
R40 (aka V40/A40i/T3) and A10/A20 share the same EMAC IP.
However, on R40 the EMAC is gated by default.

Signed-off-by: Evgeny Boger 
---
 drivers/net/ethernet/allwinner/sun4i-emac.c | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c 
b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 5ed80d9a6b9f..c0ae06dd922c 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "sun4i-emac.h"
@@ -85,6 +86,7 @@ struct emac_board_info {
unsigned intlink;
unsigned intspeed;
unsigned intduplex;
+   struct reset_control *reset;
 
phy_interface_t phy_interface;
 };
@@ -791,6 +793,7 @@ static int emac_probe(struct platform_device *pdev)
struct net_device *ndev;
int ret = 0;
const char *mac_addr;
+   struct reset_control *reset;
 
ndev = alloc_etherdev(sizeof(struct emac_board_info));
if (!ndev) {
@@ -852,6 +855,19 @@ static int emac_probe(struct platform_device *pdev)
goto out_release_sram;
}
 
+   reset = devm_reset_control_get_optional_exclusive(>dev, NULL);
+   if (IS_ERR(reset)) {
+   dev_err(>dev, "unable to request reset\n");
+   ret = -ENODEV;
+   goto out_release_sram;
+   }
+   db->reset = reset;
+   ret = reset_control_deassert(db->reset);
+   if (ret) {
+   dev_err(>dev, "could not deassert EMAC reset\n");
+   goto out_release_sram;
+   }
+
/* Read MAC-address from DT */
mac_addr = of_get_mac_address(np);
if (!IS_ERR(mac_addr))
@@ -881,7 +897,7 @@ static int emac_probe(struct platform_device *pdev)
if (ret) {
dev_err(>dev, "Registering netdev failed!\n");
ret = -ENODEV;
-   goto out_release_sram;
+   goto out_assert_reset;
}
 
dev_info(>dev, "%s: at %p, IRQ %d MAC: %pM\n",
@@ -889,6 +905,8 @@ static int emac_probe(struct platform_device *pdev)
 
return 0;
 
+out_assert_reset:
+   reset_control_assert(db->reset);
 out_release_sram:
sunxi_sram_release(>dev);
 out_clk_disable_unprepare:
@@ -913,6 +931,7 @@ static int emac_remove(struct platform_device *pdev)
unregister_netdev(ndev);
sunxi_sram_release(>dev);
clk_disable_unprepare(db->clk);
+   reset_control_assert(db->reset);
irq_dispose_mapping(ndev->irq);
iounmap(db->membase);
free_netdev(ndev);
-- 
2.17.1



[PATCH 2/2] dts: r40: add second ethernet support

2021-03-06 Thread Evgeny Boger
R40 (aka V40, A40i, T3) has two different Ethernet IP
called EMAC and GMAC.
EMAC only support 10/100 Mbit in MII mode,
while GMAC support both 10/100 (MII) and 10/100/1000 (RGMII).

In contrast to A10/A20 where GMAC and EMAC share the same pins
making EMAC somewhat pointless, on R40 EMAC can be routed to port H.
Both EMAC (on port H) and GMAC (on port A)
 can be then enabled at the same time, allowing for two ethernet ports.

Signed-off-by: Evgeny Boger 
---
 arch/arm/boot/dts/sun8i-r40.dtsi | 53 
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index d5ad3b9efd12..c102c1510012 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -217,6 +217,20 @@
#size-cells = <1>;
ranges;
 
+   sram_a: sram@0 {
+   compatible = "mmio-sram";
+   reg = <0x 0xc000>;
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges = <0 0x 0xc000>;
+
+   emac_sram: sram-section@8000 {
+   compatible = 
"allwinner,sun4i-a10-sram-a3-a4";
+   reg = <0x8000 0x4000>;
+   status = "okay";
+   };
+   };
+
sram_c: sram@1d0 {
compatible = "mmio-sram";
reg = <0x01d0 0xd>;
@@ -541,6 +555,24 @@
drive-strength = <40>;
};
 
+   emac_ph_pins: emac-ph-pins {
+   pins = "PH8", "PH9", "PH10", "PH11",
+  "PH14", "PH15", "PH16", "PH17",
+  "PH18","PH19", "PH20", "PH21",
+  "PH22", "PH23", "PH24", "PH25",
+  "PH26", "PH27";
+   function = "emac";
+   };
+
+   emac_pa_pins: emac-pa-pins {
+   pins = "PA0", "PA1", "PA2",
+  "PA3", "PA4", "PA5", "PA6",
+  "PA7", "PA8", "PA9", "PA10",
+  "PA11", "PA12", "PA13", "PA14",
+  "PA15", "PA16";
+   function = "emac";
+   };
+
i2c0_pins: i2c0-pins {
pins = "PB0", "PB1";
function = "i2c0";
@@ -885,6 +917,27 @@
};
};
 
+   emac: ethernet@1c0b000 {
+   syscon = <>;
+   compatible = "allwinner,sun4i-a10-emac";
+   reg = <0x01c0b000 0x1000>;
+   interrupts = ;
+   clocks = < CLK_BUS_EMAC>;
+   resets = < RST_BUS_EMAC>;
+   allwinner,sram = <_sram 1>;
+   pinctrl-names = "default";
+   pinctrl-0 = <_ph_pins>;
+   status = "disabled";
+   };
+
+   emac_mdio: mdio@1c0b080 {
+   compatible = "allwinner,sun4i-a10-mdio";
+   reg = <0x01c0b080 0x14>;
+   status = "disabled";
+   #address-cells = <1>;
+   #size-cells = <0>;
+   };
+
mbus: dram-controller@1c62000 {
compatible = "allwinner,sun8i-r40-mbus";
reg = <0x01c62000 0x1000>;
-- 
2.17.1



[PATCH 0/2] sun8i: r40: second ethernet support

2021-03-06 Thread Evgeny Boger


This patch series adds support for two Ethernet ports on Allwinner R40.

R40 (aka V40,A40i,T3) has two different Ethernet IPs called EMAC and GMAC.
EMAC only support 10/100 Mbit in MII mode, while GMAC support both 10/100
(MII) and 10/100/1000 (RGMII).

In contrast to A10/A20 where GMAC and EMAC share the same pins making EMAC
somewhat pointless, on R40 EMAC can be routed to port H.
Both EMAC (on port H) and GMAC (on port A) can be then enabled at the same 
time, allowing for two ethernet ports.


Evgeny Boger (2):
  net: allwinner: reset control support
  dts: r40: add second ethernet support

 arch/arm/boot/dts/sun8i-r40.dtsi| 53 +
 drivers/net/ethernet/allwinner/sun4i-emac.c | 21 +++-
 2 files changed, 73 insertions(+), 1 deletion(-)

-- 
2.17.1



[PATCH] iio: adc: axp20x_adc: fix charging current reporting on AXP22x

2021-03-06 Thread Evgeny Boger
Both the charging and discharging currents on AXP22x are stored as
12-bit integers, in accordance with the datasheet.
It's also confirmed by vendor BSP (axp20x_adc.c:axp22_icharge_to_mA).

The scale factor of 0.5 is never mentioned in datasheet, nor in the
vendor source code. I think it was here to compensate for
erroneous additional bit in register width.

Tested on custom A40i+AXP221s board with external ammeter as
a reference.

Signed-off-by: Evgeny Boger 
---
 drivers/iio/adc/axp20x_adc.c | 14 ++
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 3e0c0233b431..8db6699c20c3 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -253,17 +253,7 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
struct axp20x_adc_iio *info = iio_priv(indio_dev);
int size;
 
-   /*
-* N.B.: Unlike the Chinese datasheets tell, the charging current is
-* stored on 12 bits, not 13 bits. Only discharging current is on 13
-* bits.
-*/
-   if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
-   size = 13;
-   else
-   size = 12;
-
-   *val = axp20x_read_variable_width(info->regmap, chan->address, size);
+   *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
if (*val < 0)
return *val;
 
@@ -387,7 +377,7 @@ static int axp22x_adc_scale(struct iio_chan_spec const 
*chan, int *val,
 
case IIO_CURRENT:
*val = 0;
-   *val2 = 50;
+   *val2 = 100;
return IIO_VAL_INT_PLUS_MICRO;
 
case IIO_TEMP:
-- 
2.17.1



Re: [PATCH] Add support for always enabled watchdog timers

2014-09-06 Thread Evgeny Boger

On 08/23/2014 09:33 PM, Guenter Roeck wrote:

On 08/23/2014 10:25 AM, Alexander Shiyan wrote:

Sat, 23 Aug 2014 10:16:08 -0700 от Guenter Roeck :

On 08/16/2014 05:45 PM, Evgeny Boger wrote:

From: Evgeny Boger 

Add option to use with watchdog timers which are always enabled
in hardware, i.e. there is no way to enable/disable it via GPIO pin.
The driver will start pinging WDT immediately upon loading
and will continue to do so even after stopping the watchdog.


The headline needs a reference to the affected driver.

Also, please copy the dt mailing list and maintainers.


Signed-off-by: Evgeny Boger 
---
   .../devicetree/bindings/watchdog/gpio-wdt.txt  | 14 ++-
   drivers/watchdog/gpio_wdt.c| 45 
+-

   2 files changed, 48 insertions(+), 11 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt 
b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt

index 37afec1..1f8ca46 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -12,8 +12,11 @@ Required Properties:
   the opposite level disables the WDT. Active level is determined
   by the GPIO flags.
   - hw_margin_ms: Maximum time to reset watchdog circuit 
(milliseconds).

+- always-enabled: Use with wathdog timer which is always enabled


Similar to NOWAYOUT?


I think this one is different. NOWAYOUT is a software flag, while
the flag here is supposed to mean that the hardware watchdog
is always enabled and running, and can not be disabled. Or at least
this is my understanding.


exactly



Guenter




--
С уважением,
Евгений Богер
ООО Бесконтактные устройства
http://contactless.ru
+7 (919) 965 88 36

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] Add support for always enabled watchdog timers to gpio_wdt driver

2014-09-06 Thread Evgeny Boger
From: Evgeny Boger 

Add option to use with watchdog timers which are always enabled
in hardware, i.e. there is no way to enable/disable it via GPIO pin.
The driver will start pinging WDT immediately upon loading
and will continue to do so even after stopping the watchdog.

Signed-off-by: Evgeny Boger 
---

Changes since v1:
* fixed typos and indentation
* gpio_wdt_start_timer renamed to gpio_wdt_start_hwping. 
  This function actually starts the timer to ping hardware.
  I personally find both proposed gpio_wdt_enable and __gpio_wdt_start 
  names discouraging in this context.
* fixed broken error handling for register_reboot_notifier

 .../devicetree/bindings/watchdog/gpio-wdt.txt  | 14 ++-
 drivers/watchdog/gpio_wdt.c| 46 +-
 2 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt 
b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
index 37afec1..047fe3f 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -12,8 +12,11 @@ Required Properties:
 the opposite level disables the WDT. Active level is determined
 by the GPIO flags.
 - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
+- always-enabled: Use with watchdog timer which is always enabled
+  in hardware, i.e. there is no way to enable/disable it via GPIO pin.
+  Driver will start pinging WDT immediately upon loading.
 
-Example:
+Examples:
watchdog: watchdog {
/* ADM706 */
compatible = "linux,wdt-gpio";
@@ -21,3 +24,12 @@ Example:
hw_algo = "toggle";
hw_margin_ms = <1600>;
};
+
+   watchdog: watchdog {
+   /* TPS3813 */
+   compatible = "linux,wdt-gpio";
+   gpios = < 9 GPIO_ACTIVE_LOW>;
+   hw_algo = "toggle";
+   hw_margin_ms = <1>;
+   always-enabled;
+   };
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 220a9e0..b6ab6e7 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -37,6 +37,8 @@ struct gpio_wdt_priv {
struct notifier_block   notifier;
struct timer_list   timer;
struct watchdog_device  wdd;
+   boolalways_enabled;
+   boolstarted;
 };
 
 static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
@@ -48,10 +50,8 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
gpio_direction_input(priv->gpio);
 }
 
-static int gpio_wdt_start(struct watchdog_device *wdd)
+static int gpio_wdt_start_hwping(struct gpio_wdt_priv *priv)
 {
-   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
-
priv->state = priv->active_low;
gpio_direction_output(priv->gpio, priv->state);
priv->last_jiffies = jiffies;
@@ -60,12 +60,30 @@ static int gpio_wdt_start(struct watchdog_device *wdd)
return 0;
 }
 
+static int gpio_wdt_start(struct watchdog_device *wdd)
+{
+   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+   priv->started = true;
+   if (priv->always_enabled) {
+   /* hardware ping timer is already enabled */
+   priv->last_jiffies = jiffies;
+   } else {
+   gpio_wdt_start_hwping(priv);
+   }
+
+   return 0;
+}
+
 static int gpio_wdt_stop(struct watchdog_device *wdd)
 {
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-   mod_timer(>timer, 0);
-   gpio_wdt_disable(priv);
+   priv->started = false;
+   if (!priv->always_enabled) {
+   mod_timer(>timer, 0);
+   gpio_wdt_disable(priv);
+   }
 
return 0;
 }
@@ -91,8 +109,9 @@ static void gpio_wdt_hwping(unsigned long data)
struct watchdog_device *wdd = (struct watchdog_device *)data;
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-   if (time_after(jiffies, priv->last_jiffies +
-  msecs_to_jiffies(wdd->timeout * 1000))) {
+   if (priv->started &&
+   time_after(jiffies, priv->last_jiffies +
+  msecs_to_jiffies(wdd->timeout * 1000))) {
dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
return;
}
@@ -197,6 +216,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
/* Use safe value (1/2 of real timeout) */
priv->hw_margin = msecs_to_jiffies(hw_margin / 2);
 
+   priv->always_enabled = of_property_read_bool(pdev->dev.of_node,
+   "always-enabled");
+
watchdog_set_drvdata(>wdd, priv);
 
priv->wdd.info  = _wdt_ident;
@@ -2

[PATCH v2] Add support for always enabled watchdog timers to gpio_wdt driver

2014-09-06 Thread Evgeny Boger
From: Evgeny Boger bo...@contactless.ru

Add option to use with watchdog timers which are always enabled
in hardware, i.e. there is no way to enable/disable it via GPIO pin.
The driver will start pinging WDT immediately upon loading
and will continue to do so even after stopping the watchdog.

Signed-off-by: Evgeny Boger bo...@contactless.ru
---

Changes since v1:
* fixed typos and indentation
* gpio_wdt_start_timer renamed to gpio_wdt_start_hwping. 
  This function actually starts the timer to ping hardware.
  I personally find both proposed gpio_wdt_enable and __gpio_wdt_start 
  names discouraging in this context.
* fixed broken error handling for register_reboot_notifier

 .../devicetree/bindings/watchdog/gpio-wdt.txt  | 14 ++-
 drivers/watchdog/gpio_wdt.c| 46 +-
 2 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt 
b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
index 37afec1..047fe3f 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -12,8 +12,11 @@ Required Properties:
 the opposite level disables the WDT. Active level is determined
 by the GPIO flags.
 - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
+- always-enabled: Use with watchdog timer which is always enabled
+  in hardware, i.e. there is no way to enable/disable it via GPIO pin.
+  Driver will start pinging WDT immediately upon loading.
 
-Example:
+Examples:
watchdog: watchdog {
/* ADM706 */
compatible = linux,wdt-gpio;
@@ -21,3 +24,12 @@ Example:
hw_algo = toggle;
hw_margin_ms = 1600;
};
+
+   watchdog: watchdog {
+   /* TPS3813 */
+   compatible = linux,wdt-gpio;
+   gpios = gpio3 9 GPIO_ACTIVE_LOW;
+   hw_algo = toggle;
+   hw_margin_ms = 1;
+   always-enabled;
+   };
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 220a9e0..b6ab6e7 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -37,6 +37,8 @@ struct gpio_wdt_priv {
struct notifier_block   notifier;
struct timer_list   timer;
struct watchdog_device  wdd;
+   boolalways_enabled;
+   boolstarted;
 };
 
 static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
@@ -48,10 +50,8 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
gpio_direction_input(priv-gpio);
 }
 
-static int gpio_wdt_start(struct watchdog_device *wdd)
+static int gpio_wdt_start_hwping(struct gpio_wdt_priv *priv)
 {
-   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
-
priv-state = priv-active_low;
gpio_direction_output(priv-gpio, priv-state);
priv-last_jiffies = jiffies;
@@ -60,12 +60,30 @@ static int gpio_wdt_start(struct watchdog_device *wdd)
return 0;
 }
 
+static int gpio_wdt_start(struct watchdog_device *wdd)
+{
+   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+   priv-started = true;
+   if (priv-always_enabled) {
+   /* hardware ping timer is already enabled */
+   priv-last_jiffies = jiffies;
+   } else {
+   gpio_wdt_start_hwping(priv);
+   }
+
+   return 0;
+}
+
 static int gpio_wdt_stop(struct watchdog_device *wdd)
 {
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-   mod_timer(priv-timer, 0);
-   gpio_wdt_disable(priv);
+   priv-started = false;
+   if (!priv-always_enabled) {
+   mod_timer(priv-timer, 0);
+   gpio_wdt_disable(priv);
+   }
 
return 0;
 }
@@ -91,8 +109,9 @@ static void gpio_wdt_hwping(unsigned long data)
struct watchdog_device *wdd = (struct watchdog_device *)data;
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-   if (time_after(jiffies, priv-last_jiffies +
-  msecs_to_jiffies(wdd-timeout * 1000))) {
+   if (priv-started 
+   time_after(jiffies, priv-last_jiffies +
+  msecs_to_jiffies(wdd-timeout * 1000))) {
dev_crit(wdd-dev, Timer expired. System will reboot soon!\n);
return;
}
@@ -197,6 +216,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
/* Use safe value (1/2 of real timeout) */
priv-hw_margin = msecs_to_jiffies(hw_margin / 2);
 
+   priv-always_enabled = of_property_read_bool(pdev-dev.of_node,
+   always-enabled);
+
watchdog_set_drvdata(priv-wdd, priv);
 
priv-wdd.info  = gpio_wdt_ident;
@@ -207,6 +229,7 @@ static int gpio_wdt_probe(struct platform_device *pdev)
if (watchdog_init_timeout(priv-wdd, 0, pdev-dev)  0

Re: [PATCH] Add support for always enabled watchdog timers

2014-09-06 Thread Evgeny Boger

On 08/23/2014 09:33 PM, Guenter Roeck wrote:

On 08/23/2014 10:25 AM, Alexander Shiyan wrote:

Sat, 23 Aug 2014 10:16:08 -0700 от Guenter Roeck li...@roeck-us.net:

On 08/16/2014 05:45 PM, Evgeny Boger wrote:

From: Evgeny Boger bo...@contactless.ru

Add option to use with watchdog timers which are always enabled
in hardware, i.e. there is no way to enable/disable it via GPIO pin.
The driver will start pinging WDT immediately upon loading
and will continue to do so even after stopping the watchdog.


The headline needs a reference to the affected driver.

Also, please copy the dt mailing list and maintainers.


Signed-off-by: Evgeny Boger bo...@contactless.ru
---
   .../devicetree/bindings/watchdog/gpio-wdt.txt  | 14 ++-
   drivers/watchdog/gpio_wdt.c| 45 
+-

   2 files changed, 48 insertions(+), 11 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt 
b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt

index 37afec1..1f8ca46 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -12,8 +12,11 @@ Required Properties:
   the opposite level disables the WDT. Active level is determined
   by the GPIO flags.
   - hw_margin_ms: Maximum time to reset watchdog circuit 
(milliseconds).

+- always-enabled: Use with wathdog timer which is always enabled


Similar to NOWAYOUT?


I think this one is different. NOWAYOUT is a software flag, while
the flag here is supposed to mean that the hardware watchdog
is always enabled and running, and can not be disabled. Or at least
this is my understanding.


exactly



Guenter




--
С уважением,
Евгений Богер
ООО Бесконтактные устройства
http://contactless.ru
+7 (919) 965 88 36

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


[PATCH] Add support for always enabled watchdog timers

2014-08-16 Thread Evgeny Boger
From: Evgeny Boger 

Add option to use with watchdog timers which are always enabled 
in hardware, i.e. there is no way to enable/disable it via GPIO pin.
The driver will start pinging WDT immediately upon loading
and will continue to do so even after stopping the watchdog.

Signed-off-by: Evgeny Boger 
---
 .../devicetree/bindings/watchdog/gpio-wdt.txt  | 14 ++-
 drivers/watchdog/gpio_wdt.c| 45 +-
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt 
b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
index 37afec1..1f8ca46 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -12,8 +12,11 @@ Required Properties:
 the opposite level disables the WDT. Active level is determined
 by the GPIO flags.
 - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
+- always-enabled: Use with wathdog timer which is always enabled
+  in hardware, i.e. there is no way to enable/disable it via GPIO pin.
+  Driver will start pinging WDT immediately upon loading.
 
-Example:
+Examples:
watchdog: watchdog {
/* ADM706 */
compatible = "linux,wdt-gpio";
@@ -21,3 +24,12 @@ Example:
hw_algo = "toggle";
hw_margin_ms = <1600>;
};
+
+   watchdog: watchdog {
+   /* TPS3813 */
+   compatible = "linux,wdt-gpio";
+   gpios = < 9 GPIO_ACTIVE_LOW>;
+   hw_algo = "toggle";
+   hw_margin_ms = <1>;
+   always-enabled;
+   };
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 220a9e0..29f9bff 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -37,6 +37,8 @@ struct gpio_wdt_priv {
struct notifier_block   notifier;
struct timer_list   timer;
struct watchdog_device  wdd;
+   boolalways_enabled;
+   boolstarted;
 };
 
 static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
@@ -48,10 +50,8 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
gpio_direction_input(priv->gpio);
 }
 
-static int gpio_wdt_start(struct watchdog_device *wdd)
+static int gpio_wdt_start_timer(struct gpio_wdt_priv *priv)
 {
-   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
-
priv->state = priv->active_low;
gpio_direction_output(priv->gpio, priv->state);
priv->last_jiffies = jiffies;
@@ -60,12 +60,28 @@ static int gpio_wdt_start(struct watchdog_device *wdd)
return 0;
 }
 
-static int gpio_wdt_stop(struct watchdog_device *wdd)
+static int gpio_wdt_start(struct watchdog_device *wdd)
 {
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+   priv->started = true;
+   if (priv->always_enabled) {
+   /* harware ping timer is already enabled */
+   priv->last_jiffies = jiffies;
+   } else {
+   gpio_wdt_start_timer(priv);
+   }
 
-   mod_timer(>timer, 0);
-   gpio_wdt_disable(priv);
+   return 0;
+}
+
+static int gpio_wdt_stop(struct watchdog_device *wdd)
+{
+   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+   priv->started = false;
+   if (!priv->always_enabled) {
+   mod_timer(>timer, 0);
+   gpio_wdt_disable(priv);
+   }
 
return 0;
 }
@@ -91,10 +107,12 @@ static void gpio_wdt_hwping(unsigned long data)
struct watchdog_device *wdd = (struct watchdog_device *)data;
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-   if (time_after(jiffies, priv->last_jiffies +
-  msecs_to_jiffies(wdd->timeout * 1000))) {
-   dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
-   return;
+   if (priv->started) {
+   if (time_after(jiffies, priv->last_jiffies +
+  msecs_to_jiffies(wdd->timeout * 1000))) {
+   dev_crit(wdd->dev, "Timer expired. System will reboot 
soon!\n");
+   return;
+   }
}
 
/* Restart timer */
@@ -197,6 +215,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
/* Use safe value (1/2 of real timeout) */
priv->hw_margin = msecs_to_jiffies(hw_margin / 2);
 
+   priv->always_enabled = of_property_read_bool(pdev->dev.of_node,
+   "always-enabled");
+
watchdog_set_drvdata(>wdd, priv);
 
priv->wdd.info  = _wdt_ident;
@@ -207,6 +228,7 @@ static int gpio_wdt_probe(struct platform_device *pdev)
if (watchdog_init_timeout(>

[PATCH] Add support for always enabled watchdog timers

2014-08-16 Thread Evgeny Boger
From: Evgeny Boger bo...@contactless.ru

Add option to use with watchdog timers which are always enabled 
in hardware, i.e. there is no way to enable/disable it via GPIO pin.
The driver will start pinging WDT immediately upon loading
and will continue to do so even after stopping the watchdog.

Signed-off-by: Evgeny Boger bo...@contactless.ru
---
 .../devicetree/bindings/watchdog/gpio-wdt.txt  | 14 ++-
 drivers/watchdog/gpio_wdt.c| 45 +-
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt 
b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
index 37afec1..1f8ca46 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -12,8 +12,11 @@ Required Properties:
 the opposite level disables the WDT. Active level is determined
 by the GPIO flags.
 - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
+- always-enabled: Use with wathdog timer which is always enabled
+  in hardware, i.e. there is no way to enable/disable it via GPIO pin.
+  Driver will start pinging WDT immediately upon loading.
 
-Example:
+Examples:
watchdog: watchdog {
/* ADM706 */
compatible = linux,wdt-gpio;
@@ -21,3 +24,12 @@ Example:
hw_algo = toggle;
hw_margin_ms = 1600;
};
+
+   watchdog: watchdog {
+   /* TPS3813 */
+   compatible = linux,wdt-gpio;
+   gpios = gpio3 9 GPIO_ACTIVE_LOW;
+   hw_algo = toggle;
+   hw_margin_ms = 1;
+   always-enabled;
+   };
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 220a9e0..29f9bff 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -37,6 +37,8 @@ struct gpio_wdt_priv {
struct notifier_block   notifier;
struct timer_list   timer;
struct watchdog_device  wdd;
+   boolalways_enabled;
+   boolstarted;
 };
 
 static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
@@ -48,10 +50,8 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
gpio_direction_input(priv-gpio);
 }
 
-static int gpio_wdt_start(struct watchdog_device *wdd)
+static int gpio_wdt_start_timer(struct gpio_wdt_priv *priv)
 {
-   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
-
priv-state = priv-active_low;
gpio_direction_output(priv-gpio, priv-state);
priv-last_jiffies = jiffies;
@@ -60,12 +60,28 @@ static int gpio_wdt_start(struct watchdog_device *wdd)
return 0;
 }
 
-static int gpio_wdt_stop(struct watchdog_device *wdd)
+static int gpio_wdt_start(struct watchdog_device *wdd)
 {
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+   priv-started = true;
+   if (priv-always_enabled) {
+   /* harware ping timer is already enabled */
+   priv-last_jiffies = jiffies;
+   } else {
+   gpio_wdt_start_timer(priv);
+   }
 
-   mod_timer(priv-timer, 0);
-   gpio_wdt_disable(priv);
+   return 0;
+}
+
+static int gpio_wdt_stop(struct watchdog_device *wdd)
+{
+   struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+   priv-started = false;
+   if (!priv-always_enabled) {
+   mod_timer(priv-timer, 0);
+   gpio_wdt_disable(priv);
+   }
 
return 0;
 }
@@ -91,10 +107,12 @@ static void gpio_wdt_hwping(unsigned long data)
struct watchdog_device *wdd = (struct watchdog_device *)data;
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-   if (time_after(jiffies, priv-last_jiffies +
-  msecs_to_jiffies(wdd-timeout * 1000))) {
-   dev_crit(wdd-dev, Timer expired. System will reboot soon!\n);
-   return;
+   if (priv-started) {
+   if (time_after(jiffies, priv-last_jiffies +
+  msecs_to_jiffies(wdd-timeout * 1000))) {
+   dev_crit(wdd-dev, Timer expired. System will reboot 
soon!\n);
+   return;
+   }
}
 
/* Restart timer */
@@ -197,6 +215,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
/* Use safe value (1/2 of real timeout) */
priv-hw_margin = msecs_to_jiffies(hw_margin / 2);
 
+   priv-always_enabled = of_property_read_bool(pdev-dev.of_node,
+   always-enabled);
+
watchdog_set_drvdata(priv-wdd, priv);
 
priv-wdd.info  = gpio_wdt_ident;
@@ -207,6 +228,7 @@ static int gpio_wdt_probe(struct platform_device *pdev)
if (watchdog_init_timeout(priv-wdd, 0, pdev-dev)  0)
priv-wdd.timeout = SOFT_TIMEOUT_DEF;
 
+   priv-started = false;
setup_timer(priv-timer

Re: [PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-12 Thread Evgeny Boger

11/12/2013 12:01 PM, David Fries:

On Tue, Nov 12, 2013 at 05:07:14AM +0400, Evgeny Boger wrote:

+David Fries 

Hi David,

Would you please comment on this?


On Mon, Nov 11, 2013 at 06:36:54PM +0400, Evgeny Boger wrote:

  Strong pullup is emulated by driving pin logic high after write
  command when
  using tri-state push-pull GPIO.

Not knowing the hardware involved, is driving the logic high a
stronger pullup than the normal weak pullup input high?  Meaning it
was already being left high, just with a lessor pullup and this will
provide a stronger one?





Sure. The push-pull GPIO on common SoC's are usually able to provide up 
to 10 mA of current.







On Tue, Nov 12, 2013 at 03:09:36AM +0400, Evgeniy Polyakov wrote:

+ msleep(pdata->pullup_duration);

This doesn't look like a good idea - kernel will sleep for that long
not doing usual w1 job

Not speaking for Evgeny Boger, but I'm thinking that's intended here.
The original strong pullup code change 6a158c0de791a81 I wrote will
msleep in w1_post_write when a hardware pullup isn't available, while
the hardware ds2490 ds9490r_set_pullup sleeps for the strong pullup
using spu_sleep variable.  The user requests a strong pullup for a
given time and any other operations on the bus will interrupt the
strong pullup, so locking any other operations sounds desired.


11/12/2013 05:03 AM, Evgeniy Polyakov:

Hi

12.11.2013, 03:32, "Evgeny Boger" :

Why did you drop this check? It has nothing with w1-gpio driver

This check prevents master from implementing "set_pullup"  provided it does support only 
"write_bit" method.
The comment above states that

  w1_io.c would need to support calling set_pullup before - * the last 
write_bit operation of a w1_write_8 which it currently - * doesn't.

which is kind of strange, since it describes what w1_io.c actually does support.

w1_write_8 (w1_io.c:154, 
https://github.com/torvalds/linux/blob/master/drivers/w1/w1_io.c#L154):

 for (i = 0; i < 8; ++i) {
 if (i == 7)
 w1_pre_write(dev);
 w1_touch_bit(dev, (byte >> i) & 0x1);
 }

It seems like w1_write_8() calls w1_pre_write(), which in turn calls 
set_pullup() just before the last write_bit().

I'm not seeing any harm in removing this check and clear
master->set_pullup.  It doesn't seem correct for this code to override
a master that claims to provide something of a stronger pullup.  It's
been about five years since I wrote that code, I think it was just to
protect against a stupid master.

With this patch the last w1_write_bit will go logic 1, for 64 or 10 us
before returning, then w1_gpio_set_pullup is called to enable the
strong pullup.  What I wouldn't know is if in that last bit if the
logic 1 would be a go up to the strong pullup, or if it would finish
that time slot with a weak pullup and then go to a strong pullup.  I
would have to dig into the timing specifications much more than I have
time to right now to say what is supposed to happen.  The 18b20
datasheet lists, "The DQ line must be switched over to the strong
pullup within 10 us maximum after issuing any protocol that involves
copying the E2 memory or initiates temperature conversions."  It isn't
clear where that 10 us starts from.  You might try to dig around and
see if that last bit written should go to weak pullup 1 or strong
pullup 1.  It would take more changes if it should go right to a
strong pullup.



I wasn't able to find any support for the latter statement.
It looks like the strong pull-up should be enabled *after* the last bit 
has been sent

so no need to set strong pull-up there.

However setting strong pullup for last bit makes sense just to ensure we
fit to 10us time window.

On the other hand, I didn't experienced any problems with the proposed
implementation.








I'm not sure why this check was there in the first place.

Please add author of those lines to clarify things.
This doesn't look obvious to me


--
 Evgeny
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-12 Thread Evgeny Boger
 Strong pullup is emulated by driving pin logic high after write command when
 using tri-state push-pull GPIO.


Signed-off-by: Evgeny Boger 
---
 drivers/w1/masters/w1-gpio.c | 22 ++
 drivers/w1/w1_int.c  | 12 
 include/linux/w1-gpio.h  |  1 +
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index f54ece2..cb7f89b 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -18,10 +18,31 @@
 #include 
 #include 
 #include 
+#include 

 #include "../w1.h"
 #include "../w1_int.h"

+static u8 w1_gpio_set_pullup(void *data, int delay)
+{
+   struct w1_gpio_platform_data *pdata = data;
+
+   if (delay) {
+   pdata->pullup_duration = delay;
+   } else {
+   if (pdata->pullup_duration) {
+   gpio_direction_output(pdata->pin, 1);
+
+   msleep(pdata->pullup_duration);
+
+   gpio_direction_input(pdata->pin);
+   }
+   pdata->pullup_duration = 0;
+   }
+
+   return 0;
+}
+
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
struct w1_gpio_platform_data *pdata = data;
@@ -125,6 +146,7 @@ static int w1_gpio_probe(struct platform_device *pdev)
} else {
gpio_direction_input(pdata->pin);
master->write_bit = w1_gpio_write_bit_dir;
+   master->set_pullup = w1_gpio_set_pullup;
}

err = w1_add_master_device(master);
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 5a98649..590bd8a 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -117,18 +117,6 @@ int w1_add_master_device(struct w1_bus_master *master)
printk(KERN_ERR "w1_add_master_device: invalid function set\n");
return(-EINVAL);
 }
-   /* While it would be electrically possible to make a device that
-* generated a strong pullup in bit bang mode, only hardware that
-* controls 1-wire time frames are even expected to support a strong
-* pullup.  w1_io.c would need to support calling set_pullup before
-* the last write_bit operation of a w1_write_8 which it currently
-* doesn't.
-*/
-   if (!master->write_byte && !master->touch_bit && master->set_pullup) {
-   printk(KERN_ERR "w1_add_master_device: set_pullup requires "
-   "write_byte or touch_bit, disabling\n");
-   master->set_pullup = NULL;
-   }

/* Lock until the device is added (or not) to w1_masters. */
mutex_lock(_mlock);
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
index 065e3ae..d58594a 100644
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -20,6 +20,7 @@ struct w1_gpio_platform_data {
unsigned int is_open_drain:1;
void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
+   unsigned int pullup_duration;
 };

 #endif /* _LINUX_W1_GPIO_H */
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-12 Thread Evgeny Boger
 Strong pullup is emulated by driving pin logic high after write command when
 using tri-state push-pull GPIO.


Signed-off-by: Evgeny Boger bo...@contactless.ru
---
 drivers/w1/masters/w1-gpio.c | 22 ++
 drivers/w1/w1_int.c  | 12 
 include/linux/w1-gpio.h  |  1 +
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index f54ece2..cb7f89b 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -18,10 +18,31 @@
 #include linux/of_gpio.h
 #include linux/err.h
 #include linux/of.h
+#include linux/delay.h

 #include ../w1.h
 #include ../w1_int.h

+static u8 w1_gpio_set_pullup(void *data, int delay)
+{
+   struct w1_gpio_platform_data *pdata = data;
+
+   if (delay) {
+   pdata-pullup_duration = delay;
+   } else {
+   if (pdata-pullup_duration) {
+   gpio_direction_output(pdata-pin, 1);
+
+   msleep(pdata-pullup_duration);
+
+   gpio_direction_input(pdata-pin);
+   }
+   pdata-pullup_duration = 0;
+   }
+
+   return 0;
+}
+
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
struct w1_gpio_platform_data *pdata = data;
@@ -125,6 +146,7 @@ static int w1_gpio_probe(struct platform_device *pdev)
} else {
gpio_direction_input(pdata-pin);
master-write_bit = w1_gpio_write_bit_dir;
+   master-set_pullup = w1_gpio_set_pullup;
}

err = w1_add_master_device(master);
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 5a98649..590bd8a 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -117,18 +117,6 @@ int w1_add_master_device(struct w1_bus_master *master)
printk(KERN_ERR w1_add_master_device: invalid function set\n);
return(-EINVAL);
 }
-   /* While it would be electrically possible to make a device that
-* generated a strong pullup in bit bang mode, only hardware that
-* controls 1-wire time frames are even expected to support a strong
-* pullup.  w1_io.c would need to support calling set_pullup before
-* the last write_bit operation of a w1_write_8 which it currently
-* doesn't.
-*/
-   if (!master-write_byte  !master-touch_bit  master-set_pullup) {
-   printk(KERN_ERR w1_add_master_device: set_pullup requires 
-   write_byte or touch_bit, disabling\n);
-   master-set_pullup = NULL;
-   }

/* Lock until the device is added (or not) to w1_masters. */
mutex_lock(w1_mlock);
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
index 065e3ae..d58594a 100644
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -20,6 +20,7 @@ struct w1_gpio_platform_data {
unsigned int is_open_drain:1;
void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
+   unsigned int pullup_duration;
 };

 #endif /* _LINUX_W1_GPIO_H */
--
1.8.1.2
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-12 Thread Evgeny Boger

11/12/2013 12:01 PM, David Fries:

On Tue, Nov 12, 2013 at 05:07:14AM +0400, Evgeny Boger wrote:

+David Fries da...@fries.net

Hi David,

Would you please comment on this?


On Mon, Nov 11, 2013 at 06:36:54PM +0400, Evgeny Boger wrote:

  Strong pullup is emulated by driving pin logic high after write
  command when
  using tri-state push-pull GPIO.

Not knowing the hardware involved, is driving the logic high a
stronger pullup than the normal weak pullup input high?  Meaning it
was already being left high, just with a lessor pullup and this will
provide a stronger one?





Sure. The push-pull GPIO on common SoC's are usually able to provide up 
to 10 mA of current.







On Tue, Nov 12, 2013 at 03:09:36AM +0400, Evgeniy Polyakov wrote:

+ msleep(pdata-pullup_duration);

This doesn't look like a good idea - kernel will sleep for that long
not doing usual w1 job

Not speaking for Evgeny Boger, but I'm thinking that's intended here.
The original strong pullup code change 6a158c0de791a81 I wrote will
msleep in w1_post_write when a hardware pullup isn't available, while
the hardware ds2490 ds9490r_set_pullup sleeps for the strong pullup
using spu_sleep variable.  The user requests a strong pullup for a
given time and any other operations on the bus will interrupt the
strong pullup, so locking any other operations sounds desired.


11/12/2013 05:03 AM, Evgeniy Polyakov:

Hi

12.11.2013, 03:32, Evgeny Boger eugenybo...@gmail.com:

Why did you drop this check? It has nothing with w1-gpio driver

This check prevents master from implementing set_pullup  provided it does support only 
write_bit method.
The comment above states that

  w1_io.c would need to support calling set_pullup before - * the last 
write_bit operation of a w1_write_8 which it currently - * doesn't.

which is kind of strange, since it describes what w1_io.c actually does support.

w1_write_8 (w1_io.c:154, 
https://github.com/torvalds/linux/blob/master/drivers/w1/w1_io.c#L154):

 for (i = 0; i  8; ++i) {
 if (i == 7)
 w1_pre_write(dev);
 w1_touch_bit(dev, (byte  i)  0x1);
 }

It seems like w1_write_8() calls w1_pre_write(), which in turn calls 
set_pullup() just before the last write_bit().

I'm not seeing any harm in removing this check and clear
master-set_pullup.  It doesn't seem correct for this code to override
a master that claims to provide something of a stronger pullup.  It's
been about five years since I wrote that code, I think it was just to
protect against a stupid master.

With this patch the last w1_write_bit will go logic 1, for 64 or 10 us
before returning, then w1_gpio_set_pullup is called to enable the
strong pullup.  What I wouldn't know is if in that last bit if the
logic 1 would be a go up to the strong pullup, or if it would finish
that time slot with a weak pullup and then go to a strong pullup.  I
would have to dig into the timing specifications much more than I have
time to right now to say what is supposed to happen.  The 18b20
datasheet lists, The DQ line must be switched over to the strong
pullup within 10 us maximum after issuing any protocol that involves
copying the E2 memory or initiates temperature conversions.  It isn't
clear where that 10 us starts from.  You might try to dig around and
see if that last bit written should go to weak pullup 1 or strong
pullup 1.  It would take more changes if it should go right to a
strong pullup.



I wasn't able to find any support for the latter statement.
It looks like the strong pull-up should be enabled *after* the last bit 
has been sent

so no need to set strong pull-up there.

However setting strong pullup for last bit makes sense just to ensure we
fit to 10us time window.

On the other hand, I didn't experienced any problems with the proposed
implementation.








I'm not sure why this check was there in the first place.

Please add author of those lines to clarify things.
This doesn't look obvious to me


--
 Evgeny
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-11 Thread Evgeny Boger

+David Fries 

Hi David,

Would you please comment on this?


11/12/2013 05:03 AM, Evgeniy Polyakov:

Hi

12.11.2013, 03:32, "Evgeny Boger" :

Why did you drop this check? It has nothing with w1-gpio driver

This check prevents master from implementing "set_pullup"  provided it does support only 
"write_bit" method.
The comment above states that

  w1_io.c would need to support calling set_pullup before - * the last 
write_bit operation of a w1_write_8 which it currently - * doesn't.

which is kind of strange, since it describes what w1_io.c actually does support.

w1_write_8 (w1_io.c:154, 
https://github.com/torvalds/linux/blob/master/drivers/w1/w1_io.c#L154):

 for (i = 0; i < 8; ++i) {
 if (i == 7)
 w1_pre_write(dev);
 w1_touch_bit(dev, (byte >> i) & 0x1);
 }

It seems like w1_write_8() calls w1_pre_write(), which in turn calls 
set_pullup() just before the last write_bit().

I'm not sure why this check was there in the first place.

Please add author of those lines to clarify things.
This doesn't look obvious to me


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-11 Thread Evgeny Boger
 Strong pullup is emulated by driving pin logic high after write command when
 using tri-state push-pull GPIO.


Signed-off-by: Evgeny Boger 
---
 drivers/w1/masters/w1-gpio.c | 22 ++
 drivers/w1/w1_int.c  | 12 
 include/linux/w1-gpio.h  |  1 +
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index f54ece2..cb7f89b 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -18,10 +18,31 @@
 #include 
 #include 
 #include 
+#include 

 #include "../w1.h"
 #include "../w1_int.h"

+static u8 w1_gpio_set_pullup(void *data, int delay)
+{
+   struct w1_gpio_platform_data *pdata = data;
+
+   if (delay) {
+   pdata->pullup_duration = delay;
+   } else {
+   if (pdata->pullup_duration) {
+   gpio_direction_output(pdata->pin, 1);
+
+   msleep(pdata->pullup_duration);
+
+   gpio_direction_input(pdata->pin);
+   }
+   pdata->pullup_duration = 0;
+   }
+
+   return 0;
+}
+
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
struct w1_gpio_platform_data *pdata = data;
@@ -125,6 +146,7 @@ static int w1_gpio_probe(struct platform_device *pdev)
} else {
gpio_direction_input(pdata->pin);
master->write_bit = w1_gpio_write_bit_dir;
+   master->set_pullup = w1_gpio_set_pullup;
}

err = w1_add_master_device(master);
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 5a98649..590bd8a 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -117,18 +117,6 @@ int w1_add_master_device(struct w1_bus_master *master)
printk(KERN_ERR "w1_add_master_device: invalid function set\n");
return(-EINVAL);
 }
-   /* While it would be electrically possible to make a device that
-* generated a strong pullup in bit bang mode, only hardware that
-* controls 1-wire time frames are even expected to support a strong
-* pullup.  w1_io.c would need to support calling set_pullup before
-* the last write_bit operation of a w1_write_8 which it currently
-* doesn't.
-*/
-   if (!master->write_byte && !master->touch_bit && master->set_pullup) {
-   printk(KERN_ERR "w1_add_master_device: set_pullup requires "
-   "write_byte or touch_bit, disabling\n");
-   master->set_pullup = NULL;
-   }

/* Lock until the device is added (or not) to w1_masters. */
mutex_lock(_mlock);
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
index 065e3ae..d58594a 100644
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -20,6 +20,7 @@ struct w1_gpio_platform_data {
unsigned int is_open_drain:1;
void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
+   unsigned int pullup_duration;
 };

 #endif /* _LINUX_W1_GPIO_H */
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-11 Thread Evgeny Boger
 Strong pullup is emulated by driving pin logic high after write command when
 using tri-state push-pull GPIO.


Signed-off-by: Evgeny Boger bo...@contactless.ru
---
 drivers/w1/masters/w1-gpio.c | 22 ++
 drivers/w1/w1_int.c  | 12 
 include/linux/w1-gpio.h  |  1 +
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index f54ece2..cb7f89b 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -18,10 +18,31 @@
 #include linux/of_gpio.h
 #include linux/err.h
 #include linux/of.h
+#include linux/delay.h

 #include ../w1.h
 #include ../w1_int.h

+static u8 w1_gpio_set_pullup(void *data, int delay)
+{
+   struct w1_gpio_platform_data *pdata = data;
+
+   if (delay) {
+   pdata-pullup_duration = delay;
+   } else {
+   if (pdata-pullup_duration) {
+   gpio_direction_output(pdata-pin, 1);
+
+   msleep(pdata-pullup_duration);
+
+   gpio_direction_input(pdata-pin);
+   }
+   pdata-pullup_duration = 0;
+   }
+
+   return 0;
+}
+
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
struct w1_gpio_platform_data *pdata = data;
@@ -125,6 +146,7 @@ static int w1_gpio_probe(struct platform_device *pdev)
} else {
gpio_direction_input(pdata-pin);
master-write_bit = w1_gpio_write_bit_dir;
+   master-set_pullup = w1_gpio_set_pullup;
}

err = w1_add_master_device(master);
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 5a98649..590bd8a 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -117,18 +117,6 @@ int w1_add_master_device(struct w1_bus_master *master)
printk(KERN_ERR w1_add_master_device: invalid function set\n);
return(-EINVAL);
 }
-   /* While it would be electrically possible to make a device that
-* generated a strong pullup in bit bang mode, only hardware that
-* controls 1-wire time frames are even expected to support a strong
-* pullup.  w1_io.c would need to support calling set_pullup before
-* the last write_bit operation of a w1_write_8 which it currently
-* doesn't.
-*/
-   if (!master-write_byte  !master-touch_bit  master-set_pullup) {
-   printk(KERN_ERR w1_add_master_device: set_pullup requires 
-   write_byte or touch_bit, disabling\n);
-   master-set_pullup = NULL;
-   }

/* Lock until the device is added (or not) to w1_masters. */
mutex_lock(w1_mlock);
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
index 065e3ae..d58594a 100644
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -20,6 +20,7 @@ struct w1_gpio_platform_data {
unsigned int is_open_drain:1;
void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
+   unsigned int pullup_duration;
 };

 #endif /* _LINUX_W1_GPIO_H */
--
1.8.1.2
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/1] Add strong pullup emulation to w1-gpio master driver.

2013-11-11 Thread Evgeny Boger

+David Fries da...@fries.net

Hi David,

Would you please comment on this?


11/12/2013 05:03 AM, Evgeniy Polyakov:

Hi

12.11.2013, 03:32, Evgeny Boger eugenybo...@gmail.com:

Why did you drop this check? It has nothing with w1-gpio driver

This check prevents master from implementing set_pullup  provided it does support only 
write_bit method.
The comment above states that

  w1_io.c would need to support calling set_pullup before - * the last 
write_bit operation of a w1_write_8 which it currently - * doesn't.

which is kind of strange, since it describes what w1_io.c actually does support.

w1_write_8 (w1_io.c:154, 
https://github.com/torvalds/linux/blob/master/drivers/w1/w1_io.c#L154):

 for (i = 0; i  8; ++i) {
 if (i == 7)
 w1_pre_write(dev);
 w1_touch_bit(dev, (byte  i)  0x1);
 }

It seems like w1_write_8() calls w1_pre_write(), which in turn calls 
set_pullup() just before the last write_bit().

I'm not sure why this check was there in the first place.

Please add author of those lines to clarify things.
This doesn't look obvious to me


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