Re: [linux-sunxi] [PATCH 1/9] sun6i: Add new p2wi controller driver

2014-11-05 Thread Hans de Goede
Hi,

On 11/03/2014 04:59 PM, Chen-Yu Tsai wrote:
> Hi,
> 
> On Mon, Nov 3, 2014 at 11:34 PM, Hans de Goede  wrote:
>> From: Oliver Schinagl 
>>
>> The A31 uses a new push-pull two wire interface, which features higher
>> transfer speeds (upto 6 MHz) in theory. While the hardware can burst 8
>> bytes each time, this driver will only see very little use and thus is
>> limited to single byte transmission only.
>>
>> Signed-off-by: Oliver Schinagl 
>> Signed-off-by: Hans de Goede 
>> ---
>>  arch/arm/cpu/armv7/sunxi/Makefile  |   1 +
>>  arch/arm/cpu/armv7/sunxi/p2wi.c| 117 +++
>>  arch/arm/include/asm/arch-sunxi/gpio.h |   3 +
>>  arch/arm/include/asm/arch-sunxi/p2wi.h | 140 
>> +
>>  4 files changed, 261 insertions(+)
>>  create mode 100644 arch/arm/cpu/armv7/sunxi/p2wi.c
>>  create mode 100644 arch/arm/include/asm/arch-sunxi/p2wi.h
>>
>> diff --git a/arch/arm/cpu/armv7/sunxi/Makefile 
>> b/arch/arm/cpu/armv7/sunxi/Makefile
>> index 82dbf76..b3a3601 100644
>> --- a/arch/arm/cpu/armv7/sunxi/Makefile
>> +++ b/arch/arm/cpu/armv7/sunxi/Makefile
>> @@ -13,6 +13,7 @@ obj-y += clock.o
>>  obj-y  += pinmux.o
>>  obj-$(CONFIG_MACH_SUN6I)   += prcm.o
>>  obj-$(CONFIG_MACH_SUN8I)   += prcm.o
>> +obj-$(CONFIG_MACH_SUN6I)   += p2wi.o
>>  obj-$(CONFIG_MACH_SUN4I)   += clock_sun4i.o
>>  obj-$(CONFIG_MACH_SUN5I)   += clock_sun4i.o
>>  obj-$(CONFIG_MACH_SUN6I)   += clock_sun6i.o
>> diff --git a/arch/arm/cpu/armv7/sunxi/p2wi.c 
>> b/arch/arm/cpu/armv7/sunxi/p2wi.c
>> new file mode 100644
>> index 000..10df348
>> --- /dev/null
>> +++ b/arch/arm/cpu/armv7/sunxi/p2wi.c
>> @@ -0,0 +1,117 @@
>> +/*
>> + * Sunxi A31 Power Management Unit
>> + *
>> + * (C) Copyright 2013 Oliver Schinagl 
>> + * http://linux-sunxi.org
>> + *
>> + * Based on sun6i sources and earlier U-Boot Allwiner A10 SPL work
>> + *
>> + * (C) Copyright 2006-2013
>> + * Allwinner Technology Co., Ltd. 
>> + * Berg Xing 
>> + * Tom Cubie 
>> + *
>> + * SPDX-License-Identifier:GPL-2.0+
>> + */
>> +
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +
>> +void p2wi_init(void)
>> +{
>> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
>> *)SUNXI_P2WI_BASE;
>> +
>> +   /* Enable p2wi and PIO clk, and de-assert their resets */
>> +   prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI);
>> +
>> +   sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUNXI_GPL0_R_P2WI_SCK);
>> +   sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUNXI_GPL1_R_P2WI_SDA);
>> +
>> +   /* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz */
>> +   writel(P2WI_CTRL_RESET, &p2wi->ctrl);
>> +   sdelay(0x100);
>> +   writel(P2WI_CC_SDA_OUT_DELAY(1) | P2WI_CC_CLK_DIV(8),
>> +  &p2wi->cc);
>> +}
>> +
>> +int p2wi_set_pmu_address(u8 slave_addr, u8 ctrl_reg, u8 init_data)
> 
> set_pmu_address is actually a misnomer. What it actually does is
> write  to  on device found at ,
> probably using I2C, with the sole purpose of putting the device
> into P2WI mode (or RSB mode for later AXPs).
> 
> According to the docs/code we have, it is always writing 0x3e to
> register 0x3e.

I've renamed this to p2wi_change_to_p2wi_mode for the next version
of this patch-set.

>> +{
>> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
>> *)SUNXI_P2WI_BASE;
>> +   unsigned long tmo = timer_get_us() + 100;
>> +
>> +   writel(P2WI_PM_DEV_ADDR(slave_addr) |
>> +  P2WI_PM_CTRL_ADDR(ctrl_reg) |
>> +  P2WI_PM_INIT_DATA(init_data) |
>> +  P2WI_PM_INIT_SEND,
>> +  &p2wi->pm);
>> +
>> +   while ((readl(&p2wi->pm) & P2WI_PM_INIT_SEND)) {
>> +   if (timer_get_us() > tmo)
>> +   return -EFAULT;
>> +   }
>> +
>> +   return 0;
>> +}
>> +
>> +static int p2wi_await_trans(void)
>> +{
>> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
>> *)SUNXI_P2WI_BASE;
>> +   unsigned long tmo = timer_get_us() + 100;
>> +   int ret;
>> +   u8 reg;
>> +
>> +   while (1) {
>> +   reg = readl(&p2wi->status);
>> +   if (reg & P2WI_STAT_TRANS_ERR) {
>> +   ret = -EIO;
>> +   break;
>> +   }
>> +   if (reg & P2WI_STAT_TRANS_DONE) {
>> +   ret = 0;
>> +   break;
>> +   }
>> +   if (timer_get_us() > tmo) {
>> +   ret = -ETIME;
>> +   break;
>> +   }
>> +   }
>> +   writel(reg, &p2wi->status); /* Clear status bits */
>> +   return ret;
>> +}
>> +
>> +int p2wi_read(const u8 addr, u8 *data)
>> +{
>> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
>> *)SUNXI_P2WI_BASE;
>> +   int ret;
>> +
>> +   writel(P2WI_DATADDR_BYTE_1(addr), &p2wi->dataddr0);
>> +   writel(P2

Re: [linux-sunxi] [PATCH 1/9] sun6i: Add new p2wi controller driver

2014-11-03 Thread Chen-Yu Tsai
Hi,

On Tue, Nov 4, 2014 at 2:10 PM, Olliver Schinagl  wrote:
> Hy Wens,
>
> This is some really old work, and I'm assuming hans picked it up, as I never
> tested the code (didn't have hardware at the time)

I believe Hans did pick it up for u-boot-sunxi, and now we're just mainlining
it.

> I'll comment as I remember it and hope that helps.
>
> On a side note, do we know what p2wi stands for? I'm guessing 2wi is
> allwinners try at combining the names twi and i2c, as i2c is some philips
> trademark and maybe they think twi is an avr amongst others? so using 2wi is
> save? And the P, 'program twi? Powermanagment twi?

It stands for Push-pull 2 wire interface.

>
> If that is whats happening here, I'd be inclined to rename it to to just
> regular twi, maybe axp_twi if we must?

It's not the same. Normal TWI uses an open-drain setup. Other specifics
may be different as well, like request framing. Also P2WI does not have
the concept of device addresses.

> Olliver
>
>
> On 03-11-14 16:59, Chen-Yu Tsai wrote:
>>
>> Hi,
>>
>> On Mon, Nov 3, 2014 at 11:34 PM, Hans de Goede 
>> wrote:
>>>
>>> From: Oliver Schinagl 
>>>
>>> The A31 uses a new push-pull two wire interface, which features higher
>>> transfer speeds (upto 6 MHz) in theory. While the hardware can burst 8
>>> bytes each time, this driver will only see very little use and thus is
>>> limited to single byte transmission only.
>>>
>>> Signed-off-by: Oliver Schinagl 
>>> Signed-off-by: Hans de Goede 
>>> ---
>>>   arch/arm/cpu/armv7/sunxi/Makefile  |   1 +
>>>   arch/arm/cpu/armv7/sunxi/p2wi.c| 117
>>> +++
>>>   arch/arm/include/asm/arch-sunxi/gpio.h |   3 +
>>>   arch/arm/include/asm/arch-sunxi/p2wi.h | 140
>>> +
>>>   4 files changed, 261 insertions(+)
>>>   create mode 100644 arch/arm/cpu/armv7/sunxi/p2wi.c
>>>   create mode 100644 arch/arm/include/asm/arch-sunxi/p2wi.h
>>>
>>> diff --git a/arch/arm/cpu/armv7/sunxi/Makefile
>>> b/arch/arm/cpu/armv7/sunxi/Makefile
>>> index 82dbf76..b3a3601 100644
>>> --- a/arch/arm/cpu/armv7/sunxi/Makefile
>>> +++ b/arch/arm/cpu/armv7/sunxi/Makefile
>>> @@ -13,6 +13,7 @@ obj-y += clock.o
>>>   obj-y  += pinmux.o
>>>   obj-$(CONFIG_MACH_SUN6I)   += prcm.o
>>>   obj-$(CONFIG_MACH_SUN8I)   += prcm.o
>>> +obj-$(CONFIG_MACH_SUN6I)   += p2wi.o
>>>   obj-$(CONFIG_MACH_SUN4I)   += clock_sun4i.o
>>>   obj-$(CONFIG_MACH_SUN5I)   += clock_sun4i.o
>>>   obj-$(CONFIG_MACH_SUN6I)   += clock_sun6i.o
>>> diff --git a/arch/arm/cpu/armv7/sunxi/p2wi.c
>>> b/arch/arm/cpu/armv7/sunxi/p2wi.c
>>> new file mode 100644
>>> index 000..10df348
>>> --- /dev/null
>>> +++ b/arch/arm/cpu/armv7/sunxi/p2wi.c
>>> @@ -0,0 +1,117 @@
>>> +/*
>>> + * Sunxi A31 Power Management Unit
>>> + *
>>> + * (C) Copyright 2013 Oliver Schinagl 
>>> + * http://linux-sunxi.org
>>> + *
>>> + * Based on sun6i sources and earlier U-Boot Allwiner A10 SPL work
>>> + *
>>> + * (C) Copyright 2006-2013
>>> + * Allwinner Technology Co., Ltd. 
>>> + * Berg Xing 
>>> + * Tom Cubie 
>>> + *
>>> + * SPDX-License-Identifier:GPL-2.0+
>>> + */
>>> +
>>> +#include 
>>> +#include 
>>> +#include 
>>> +#include 
>>> +#include 
>>> +#include 
>>> +#include 
>>> +#include 
>>> +#include 
>>> +
>>> +void p2wi_init(void)
>>> +{
>>> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg
>>> *)SUNXI_P2WI_BASE;
>>> +
>>> +   /* Enable p2wi and PIO clk, and de-assert their resets */
>>> +   prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI);
>>> +
>>> +   sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUNXI_GPL0_R_P2WI_SCK);
>>> +   sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUNXI_GPL1_R_P2WI_SDA);
>>> +
>>> +   /* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz
>>> */
>>> +   writel(P2WI_CTRL_RESET, &p2wi->ctrl);
>>> +   sdelay(0x100);
>>> +   writel(P2WI_CC_SDA_OUT_DELAY(1) | P2WI_CC_CLK_DIV(8),
>>> +  &p2wi->cc);
>>> +}
>>> +
>>> +int p2wi_set_pmu_address(u8 slave_addr, u8 ctrl_reg, u8 init_data)
>>
>> set_pmu_address is actually a misnomer. What it actually does is
>> write  to  on device found at ,
>> probably using I2C, with the sole purpose of putting the device
>> into P2WI mode (or RSB mode for later AXPs).
>>
>> According to the docs/code we have, it is always writing 0x3e to
>> register 0x3e.
>
> Back then, we didn't have no official docs, nor official code ;)
>
> I think this is what boot0 for a31 called it, or something close to it. Do
> you know what other AXP's take for this ?

The AXP806 datasheet says 0x7c, which is 0x3e left shifted by 1 bit.
And the RSB driver for U-boot from Allwinner does use 0x7c.

So my guess is 0x3e for P2WI and 0x7c for RSB.

Also note that with RSB, it is still written to 0x3e on the slaves,
but to all slaves, using the slave address 0x00.

> What are the chances, that 0x3e (in this chip) does what you say, enable
> p2wi or RSB mode? If that would be the case, a more generic function would
> be nice indeed

Re: [linux-sunxi] [PATCH 1/9] sun6i: Add new p2wi controller driver

2014-11-03 Thread Olliver Schinagl

Hy Wens,

This is some really old work, and I'm assuming hans picked it up, as I 
never tested the code (didn't have hardware at the time)


I'll comment as I remember it and hope that helps.

On a side note, do we know what p2wi stands for? I'm guessing 2wi is 
allwinners try at combining the names twi and i2c, as i2c is some 
philips trademark and maybe they think twi is an avr amongst others? so 
using 2wi is save? And the P, 'program twi? Powermanagment twi?


If that is whats happening here, I'd be inclined to rename it to to just 
regular twi, maybe axp_twi if we must?


Olliver

On 03-11-14 16:59, Chen-Yu Tsai wrote:

Hi,

On Mon, Nov 3, 2014 at 11:34 PM, Hans de Goede  wrote:

From: Oliver Schinagl 

The A31 uses a new push-pull two wire interface, which features higher
transfer speeds (upto 6 MHz) in theory. While the hardware can burst 8
bytes each time, this driver will only see very little use and thus is
limited to single byte transmission only.

Signed-off-by: Oliver Schinagl 
Signed-off-by: Hans de Goede 
---
  arch/arm/cpu/armv7/sunxi/Makefile  |   1 +
  arch/arm/cpu/armv7/sunxi/p2wi.c| 117 +++
  arch/arm/include/asm/arch-sunxi/gpio.h |   3 +
  arch/arm/include/asm/arch-sunxi/p2wi.h | 140 +
  4 files changed, 261 insertions(+)
  create mode 100644 arch/arm/cpu/armv7/sunxi/p2wi.c
  create mode 100644 arch/arm/include/asm/arch-sunxi/p2wi.h

diff --git a/arch/arm/cpu/armv7/sunxi/Makefile 
b/arch/arm/cpu/armv7/sunxi/Makefile
index 82dbf76..b3a3601 100644
--- a/arch/arm/cpu/armv7/sunxi/Makefile
+++ b/arch/arm/cpu/armv7/sunxi/Makefile
@@ -13,6 +13,7 @@ obj-y += clock.o
  obj-y  += pinmux.o
  obj-$(CONFIG_MACH_SUN6I)   += prcm.o
  obj-$(CONFIG_MACH_SUN8I)   += prcm.o
+obj-$(CONFIG_MACH_SUN6I)   += p2wi.o
  obj-$(CONFIG_MACH_SUN4I)   += clock_sun4i.o
  obj-$(CONFIG_MACH_SUN5I)   += clock_sun4i.o
  obj-$(CONFIG_MACH_SUN6I)   += clock_sun6i.o
diff --git a/arch/arm/cpu/armv7/sunxi/p2wi.c b/arch/arm/cpu/armv7/sunxi/p2wi.c
new file mode 100644
index 000..10df348
--- /dev/null
+++ b/arch/arm/cpu/armv7/sunxi/p2wi.c
@@ -0,0 +1,117 @@
+/*
+ * Sunxi A31 Power Management Unit
+ *
+ * (C) Copyright 2013 Oliver Schinagl 
+ * http://linux-sunxi.org
+ *
+ * Based on sun6i sources and earlier U-Boot Allwiner A10 SPL work
+ *
+ * (C) Copyright 2006-2013
+ * Allwinner Technology Co., Ltd. 
+ * Berg Xing 
+ * Tom Cubie 
+ *
+ * SPDX-License-Identifier:GPL-2.0+
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+void p2wi_init(void)
+{
+   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg *)SUNXI_P2WI_BASE;
+
+   /* Enable p2wi and PIO clk, and de-assert their resets */
+   prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI);
+
+   sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUNXI_GPL0_R_P2WI_SCK);
+   sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUNXI_GPL1_R_P2WI_SDA);
+
+   /* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz */
+   writel(P2WI_CTRL_RESET, &p2wi->ctrl);
+   sdelay(0x100);
+   writel(P2WI_CC_SDA_OUT_DELAY(1) | P2WI_CC_CLK_DIV(8),
+  &p2wi->cc);
+}
+
+int p2wi_set_pmu_address(u8 slave_addr, u8 ctrl_reg, u8 init_data)

set_pmu_address is actually a misnomer. What it actually does is
write  to  on device found at ,
probably using I2C, with the sole purpose of putting the device
into P2WI mode (or RSB mode for later AXPs).

According to the docs/code we have, it is always writing 0x3e to
register 0x3e.

Back then, we didn't have no official docs, nor official code ;)

I think this is what boot0 for a31 called it, or something close to it. 
Do you know what other AXP's take for this ?


What are the chances, that 0x3e (in this chip) does what you say, enable 
p2wi or RSB mode? If that would be the case, a more generic function 
would be nice indeed, axp_init_mode(AXP_ADDR, AXP_MODE) or something 
comes to mind?



+{
+   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg *)SUNXI_P2WI_BASE;
+   unsigned long tmo = timer_get_us() + 100;
+
+   writel(P2WI_PM_DEV_ADDR(slave_addr) |
+  P2WI_PM_CTRL_ADDR(ctrl_reg) |
+  P2WI_PM_INIT_DATA(init_data) |
+  P2WI_PM_INIT_SEND,
+  &p2wi->pm);
+
+   while ((readl(&p2wi->pm) & P2WI_PM_INIT_SEND)) {
+   if (timer_get_us() > tmo)
+   return -EFAULT;
+   }
+
+   return 0;
+}
+
+static int p2wi_await_trans(void)
+{
+   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg *)SUNXI_P2WI_BASE;
+   unsigned long tmo = timer_get_us() + 100;
+   int ret;
+   u8 reg;
+
+   while (1) {
+   reg = readl(&p2wi->status);
+   if (reg & P2WI_STAT_TRANS_ERR) {
+   ret = -EIO;
+   break;
+   }
+   if (reg & P2WI_STAT_TRANS_DONE) {
+   ret = 0;
+  

Re: [linux-sunxi] [PATCH 1/9] sun6i: Add new p2wi controller driver

2014-11-03 Thread Chen-Yu Tsai
Hi,

On Mon, Nov 3, 2014 at 11:34 PM, Hans de Goede  wrote:
> From: Oliver Schinagl 
>
> The A31 uses a new push-pull two wire interface, which features higher
> transfer speeds (upto 6 MHz) in theory. While the hardware can burst 8
> bytes each time, this driver will only see very little use and thus is
> limited to single byte transmission only.
>
> Signed-off-by: Oliver Schinagl 
> Signed-off-by: Hans de Goede 
> ---
>  arch/arm/cpu/armv7/sunxi/Makefile  |   1 +
>  arch/arm/cpu/armv7/sunxi/p2wi.c| 117 +++
>  arch/arm/include/asm/arch-sunxi/gpio.h |   3 +
>  arch/arm/include/asm/arch-sunxi/p2wi.h | 140 
> +
>  4 files changed, 261 insertions(+)
>  create mode 100644 arch/arm/cpu/armv7/sunxi/p2wi.c
>  create mode 100644 arch/arm/include/asm/arch-sunxi/p2wi.h
>
> diff --git a/arch/arm/cpu/armv7/sunxi/Makefile 
> b/arch/arm/cpu/armv7/sunxi/Makefile
> index 82dbf76..b3a3601 100644
> --- a/arch/arm/cpu/armv7/sunxi/Makefile
> +++ b/arch/arm/cpu/armv7/sunxi/Makefile
> @@ -13,6 +13,7 @@ obj-y += clock.o
>  obj-y  += pinmux.o
>  obj-$(CONFIG_MACH_SUN6I)   += prcm.o
>  obj-$(CONFIG_MACH_SUN8I)   += prcm.o
> +obj-$(CONFIG_MACH_SUN6I)   += p2wi.o
>  obj-$(CONFIG_MACH_SUN4I)   += clock_sun4i.o
>  obj-$(CONFIG_MACH_SUN5I)   += clock_sun4i.o
>  obj-$(CONFIG_MACH_SUN6I)   += clock_sun6i.o
> diff --git a/arch/arm/cpu/armv7/sunxi/p2wi.c b/arch/arm/cpu/armv7/sunxi/p2wi.c
> new file mode 100644
> index 000..10df348
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/sunxi/p2wi.c
> @@ -0,0 +1,117 @@
> +/*
> + * Sunxi A31 Power Management Unit
> + *
> + * (C) Copyright 2013 Oliver Schinagl 
> + * http://linux-sunxi.org
> + *
> + * Based on sun6i sources and earlier U-Boot Allwiner A10 SPL work
> + *
> + * (C) Copyright 2006-2013
> + * Allwinner Technology Co., Ltd. 
> + * Berg Xing 
> + * Tom Cubie 
> + *
> + * SPDX-License-Identifier:GPL-2.0+
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +void p2wi_init(void)
> +{
> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
> *)SUNXI_P2WI_BASE;
> +
> +   /* Enable p2wi and PIO clk, and de-assert their resets */
> +   prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI);
> +
> +   sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUNXI_GPL0_R_P2WI_SCK);
> +   sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUNXI_GPL1_R_P2WI_SDA);
> +
> +   /* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz */
> +   writel(P2WI_CTRL_RESET, &p2wi->ctrl);
> +   sdelay(0x100);
> +   writel(P2WI_CC_SDA_OUT_DELAY(1) | P2WI_CC_CLK_DIV(8),
> +  &p2wi->cc);
> +}
> +
> +int p2wi_set_pmu_address(u8 slave_addr, u8 ctrl_reg, u8 init_data)

set_pmu_address is actually a misnomer. What it actually does is
write  to  on device found at ,
probably using I2C, with the sole purpose of putting the device
into P2WI mode (or RSB mode for later AXPs).

According to the docs/code we have, it is always writing 0x3e to
register 0x3e.

> +{
> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
> *)SUNXI_P2WI_BASE;
> +   unsigned long tmo = timer_get_us() + 100;
> +
> +   writel(P2WI_PM_DEV_ADDR(slave_addr) |
> +  P2WI_PM_CTRL_ADDR(ctrl_reg) |
> +  P2WI_PM_INIT_DATA(init_data) |
> +  P2WI_PM_INIT_SEND,
> +  &p2wi->pm);
> +
> +   while ((readl(&p2wi->pm) & P2WI_PM_INIT_SEND)) {
> +   if (timer_get_us() > tmo)
> +   return -EFAULT;
> +   }
> +
> +   return 0;
> +}
> +
> +static int p2wi_await_trans(void)
> +{
> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
> *)SUNXI_P2WI_BASE;
> +   unsigned long tmo = timer_get_us() + 100;
> +   int ret;
> +   u8 reg;
> +
> +   while (1) {
> +   reg = readl(&p2wi->status);
> +   if (reg & P2WI_STAT_TRANS_ERR) {
> +   ret = -EIO;
> +   break;
> +   }
> +   if (reg & P2WI_STAT_TRANS_DONE) {
> +   ret = 0;
> +   break;
> +   }
> +   if (timer_get_us() > tmo) {
> +   ret = -ETIME;
> +   break;
> +   }
> +   }
> +   writel(reg, &p2wi->status); /* Clear status bits */
> +   return ret;
> +}
> +
> +int p2wi_read(const u8 addr, u8 *data)
> +{
> +   struct sunxi_p2wi_reg *p2wi = (struct sunxi_p2wi_reg 
> *)SUNXI_P2WI_BASE;
> +   int ret;
> +
> +   writel(P2WI_DATADDR_BYTE_1(addr), &p2wi->dataddr0);
> +   writel(P2WI_DATA_NUM_BYTES(1) |
> +  P2WI_DATA_NUM_BYTES_READ, &p2wi->numbytes);
> +   writel(P2WI_STAT_TRANS_DONE, &p2wi->status);
> +   writel(P2WI_CTRL_TRANS_START, &p2wi->ctrl);
> +
> +   ret = p2wi_await_trans();
> +
> +   *data = readl(&p2wi->data0) & P2WI_DATA_BYTE_1_MASK;