* [PATCH V3 1/5] ARM: dts: OMAP: Add timer nodes
From: Hiremath, Vaibhav @ 2012-10-25 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50887315.2000509@ti.com>
On Thu, Oct 25, 2012 at 04:30:37, Hunter, Jon wrote:
>
> On 10/24/2012 01:17 PM, Hiremath, Vaibhav wrote:
> > On Wed, Oct 17, 2012 at 23:31:09, Hunter, Jon wrote:
> >> Add the 12 GP timers nodes present in OMAP2.
> >> Add the 12 GP timers nodes present in OMAP3.
> >> Add the 11 GP timers nodes present in OMAP4.
> >> Add the 7 GP timers nodes present in AM33xx.
> >>
> >> Add documentation for timer properties specific to OMAP.
> >>
> >> Please note that for OMAP2/3 devices, there is only one interrupt controller
> >> for the ARM CPU (which has the label "intc") and so globally define this as the
> >> interrupt parent to save duplicating the interrupt parent for all device nodes.
> >>
> >> Thanks to Vaibhav Hiremath for creating the AM33xx timer nodes. I have modified
> >> Vaibhav's original nodes adding information on which timers support a PWM
> >> output.
> >>
> >> Cc: Benoit Cousson <b-cousson@ti.com>
> >> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> >> ---
> >> .../devicetree/bindings/arm/omap/timer.txt | 29 ++++++
> >> arch/arm/boot/dts/am33xx.dtsi | 61 +++++++++++++
> >> arch/arm/boot/dts/omap2.dtsi | 86 ++++++++++++++++++
> >> arch/arm/boot/dts/omap2420.dtsi | 8 ++
> >> arch/arm/boot/dts/omap2430.dtsi | 8 ++
> >> arch/arm/boot/dts/omap3.dtsi | 96 ++++++++++++++++++++
> >> arch/arm/boot/dts/omap4.dtsi | 86 ++++++++++++++++++
> >> 7 files changed, 374 insertions(+)
> >> create mode 100644 Documentation/devicetree/bindings/arm/omap/timer.txt
> >>
> >
> > Although I have not tested this version of patch series at my end, but
> > whole patch-series Looks ok to me.
> >
> > Acked-By: Vaibhav Hiremath <hvaibhav@ti.com>
>
> Thanks. I made a couple cosmetic changes in V4 apart from the
> "interrupt-parent" addition which we are now dropping. Care to ACK
> patches 2-5 of V4?
>
Jon,
Good news, I could able to spend some time today on Timer issue on Am33xx
and figure out what is going wrong there. The register context is loosing,
which leads to failure of interrupt test cases.
Below log describes more on this,
[root at arago /]# echo 1 > /tmp/omap-test/timer/all
[ 9.156122] Testing 48042000.timer with 24000000 Hz clock ...
[root at arago /]#
[root at arago /]#
[root at arago /]#
[root at arago /]# [ 11.505497] Timer read test PASSED! No errors, 100 loops
[ 11.511493] omap_dm_timer_set_int_enable:664: irq_ena - 0
[ 11.517277] omap_dm_timer_set_int_enable:670: irq_ena - 2
[ 11.523095] omap_timer_interrupt_test:120: irq_ena - 0 [BOOOOOOOOM]
[ 12.521111] Timer interrupt test FAILED! No interrupt occurred in 1 sec
I changed the Test code as below, and not with your Timer patches, I have
tested all the timers without any issues.
So for all patch series,
Acked-Reviewed-&-Tested-By: Vaibhav Hiremath <hvaibhav@ti.com>
Test code diff:
===============
diff --git a/timer_test.c b/timer_test.c
index e502881..c87a830 100644
--- a/timer_test.c
+++ b/timer_test.c
@@ -13,6 +13,7 @@
#define OMAP1_NUM_TIMERS 8
#define OMAP2_NUM_TIMERS 11
+#define AM33XX_NUM_TIMERS 7
#define OMAP_MAX_NUM_TIMERS 12
#define OMAP_TIMER_SRC_CLKS 2
#define TIMER_TIMEOUT (msecs_to_jiffies(1000))
@@ -113,6 +114,9 @@ static int omap_timer_interrupt_test(struct omap_dm_timer *gptimer)
irq_data.gptimer = gptimer;
init_completion(&irq_data.complete);
+
+ omap_dm_timer_enable(gptimer);
+
omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
omap_dm_timer_set_load_start(gptimer, 0, 0xffffff00);
@@ -128,6 +132,8 @@ static int omap_timer_interrupt_test(struct omap_dm_timer *gptimer)
omap_dm_timer_stop(gptimer);
omap_dm_timer_set_int_enable(gptimer, 0);
+ omap_dm_timer_disable(gptimer);
+
free_irq(timer_irq, &irq_data);
return r;
@@ -141,6 +147,8 @@ static u32 omap_timer_num_timers(void)
max_num_timers = OMAP1_NUM_TIMERS;
else if (cpu_is_omap34xx() && (omap_type() == OMAP2_DEVICE_TYPE_GP))
max_num_timers = OMAP2_NUM_TIMERS + 1;
+ else if (soc_is_am33xx())
+ max_num_timers = AM33XX_NUM_TIMERS;
else
max_num_timers = OMAP2_NUM_TIMERS;
@@ -222,6 +230,7 @@ static int omap_timer_test_all(void)
}
for (i = 0; i < count; i++) {
+ pr_info("\n\n");
r = omap_timer_run_tests(gptimers[i]);
if (r)
errors += r;
Thanks,
Vaibhav
^ permalink raw reply related
* [PATCH V3 1/5] ARM: dts: OMAP: Add timer nodes
From: Jon Hunter @ 2012-10-25 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <79CD15C6BA57404B839C016229A409A83EB4A768@DBDE01.ent.ti.com>
On 10/25/2012 07:12 AM, Hiremath, Vaibhav wrote:
> On Thu, Oct 25, 2012 at 04:30:37, Hunter, Jon wrote:
>>
>> On 10/24/2012 01:17 PM, Hiremath, Vaibhav wrote:
>>> On Wed, Oct 17, 2012 at 23:31:09, Hunter, Jon wrote:
>>>> Add the 12 GP timers nodes present in OMAP2.
>>>> Add the 12 GP timers nodes present in OMAP3.
>>>> Add the 11 GP timers nodes present in OMAP4.
>>>> Add the 7 GP timers nodes present in AM33xx.
>>>>
>>>> Add documentation for timer properties specific to OMAP.
>>>>
>>>> Please note that for OMAP2/3 devices, there is only one interrupt controller
>>>> for the ARM CPU (which has the label "intc") and so globally define this as the
>>>> interrupt parent to save duplicating the interrupt parent for all device nodes.
>>>>
>>>> Thanks to Vaibhav Hiremath for creating the AM33xx timer nodes. I have modified
>>>> Vaibhav's original nodes adding information on which timers support a PWM
>>>> output.
>>>>
>>>> Cc: Benoit Cousson <b-cousson@ti.com>
>>>> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
>>>> ---
>>>> .../devicetree/bindings/arm/omap/timer.txt | 29 ++++++
>>>> arch/arm/boot/dts/am33xx.dtsi | 61 +++++++++++++
>>>> arch/arm/boot/dts/omap2.dtsi | 86 ++++++++++++++++++
>>>> arch/arm/boot/dts/omap2420.dtsi | 8 ++
>>>> arch/arm/boot/dts/omap2430.dtsi | 8 ++
>>>> arch/arm/boot/dts/omap3.dtsi | 96 ++++++++++++++++++++
>>>> arch/arm/boot/dts/omap4.dtsi | 86 ++++++++++++++++++
>>>> 7 files changed, 374 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/arm/omap/timer.txt
>>>>
>>>
>>> Although I have not tested this version of patch series at my end, but
>>> whole patch-series Looks ok to me.
>>>
>>> Acked-By: Vaibhav Hiremath <hvaibhav@ti.com>
>>
>> Thanks. I made a couple cosmetic changes in V4 apart from the
>> "interrupt-parent" addition which we are now dropping. Care to ACK
>> patches 2-5 of V4?
>>
>
> Jon,
>
> Good news, I could able to spend some time today on Timer issue on Am33xx
> and figure out what is going wrong there. The register context is loosing,
> which leads to failure of interrupt test cases.
Thanks!
> Below log describes more on this,
>
>
> [root at arago /]# echo 1 > /tmp/omap-test/timer/all
> [ 9.156122] Testing 48042000.timer with 24000000 Hz clock ...
> [root at arago /]#
> [root at arago /]#
> [root at arago /]#
> [root at arago /]# [ 11.505497] Timer read test PASSED! No errors, 100 loops
> [ 11.511493] omap_dm_timer_set_int_enable:664: irq_ena - 0
> [ 11.517277] omap_dm_timer_set_int_enable:670: irq_ena - 2
> [ 11.523095] omap_timer_interrupt_test:120: irq_ena - 0 [BOOOOOOOOM]
> [ 12.521111] Timer interrupt test FAILED! No interrupt occurred in 1 sec
>
>
> I changed the Test code as below, and not with your Timer patches, I have
> tested all the timers without any issues.
>
> So for all patch series,
>
> Acked-Reviewed-&-Tested-By: Vaibhav Hiremath <hvaibhav@ti.com>
Thanks!
>
> Test code diff:
> ===============
>
> diff --git a/timer_test.c b/timer_test.c
> index e502881..c87a830 100644
> --- a/timer_test.c
> +++ b/timer_test.c
> @@ -13,6 +13,7 @@
>
> #define OMAP1_NUM_TIMERS 8
> #define OMAP2_NUM_TIMERS 11
> +#define AM33XX_NUM_TIMERS 7
> #define OMAP_MAX_NUM_TIMERS 12
> #define OMAP_TIMER_SRC_CLKS 2
> #define TIMER_TIMEOUT (msecs_to_jiffies(1000))
> @@ -113,6 +114,9 @@ static int omap_timer_interrupt_test(struct omap_dm_timer *gptimer)
>
> irq_data.gptimer = gptimer;
> init_completion(&irq_data.complete);
> +
> + omap_dm_timer_enable(gptimer);
> +
> omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
> omap_dm_timer_set_load_start(gptimer, 0, 0xffffff00);
>
> @@ -128,6 +132,8 @@ static int omap_timer_interrupt_test(struct omap_dm_timer *gptimer)
>
> omap_dm_timer_stop(gptimer);
> omap_dm_timer_set_int_enable(gptimer, 0);
> + omap_dm_timer_disable(gptimer);
> +
Hmmm ... I am wondering if there is another bug lingering in the dmtimer
driver. Ideally, the context should be preserved by the driver.
> free_irq(timer_irq, &irq_data);
>
> return r;
> @@ -141,6 +147,8 @@ static u32 omap_timer_num_timers(void)
> max_num_timers = OMAP1_NUM_TIMERS;
> else if (cpu_is_omap34xx() && (omap_type() == OMAP2_DEVICE_TYPE_GP))
> max_num_timers = OMAP2_NUM_TIMERS + 1;
> + else if (soc_is_am33xx())
> + max_num_timers = AM33XX_NUM_TIMERS;
Thanks, I noticed that too when testing AM33xx.
Cheers
Jon
^ permalink raw reply
* [PATCH v2 0/7] I2C patches for v3.8 merge window
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
Hi,
here's another series for OMAP I2C driver. There are a few cleanups
and one very nice new feature: we can now report how many bytes
we transferred until NACK.
Note that the implemementation for OMAP-I2C turned out to be a
little more complex then I expected, mainly because of the way
I2C_CNT register behaves and because of the very buggy register
usage on that driver.
I have boot tested all patches on beagle xM (3630) and pandaboard
rev A3 (4430), will send boot-logs if anyone wants to see.
All patches are available at [1] if anyone wants an easy way to
test the patches.
Changes since v1:
- remove unnecessary omap_i2c_init() in case of NACK
- drop "i2c: omap: fix error checking"
Felipe Balbi (6):
i2c: omap: no need to access platform_device
i2c: omap: reorder exit path of omap_i2c_xfer_msg()
i2c: omap: also complete() when stat becomes zero
i2c: omap: in case of VERSION_2 read IRQSTATUS_RAW but write to
IRQSTATUS
i2c: omap: wait for transfer completion before sending STP bit
i2c: omap: implement handling for 'transferred' bytes
Shubhrajyoti D (1):
i2c: add 'transferred' field to struct i2c_msg
drivers/i2c/busses/i2c-omap.c | 124 ++++++++++++++++++++++--------------------
include/uapi/linux/i2c.h | 1 +
2 files changed, 65 insertions(+), 60 deletions(-)
--
1.8.0
^ permalink raw reply
* [PATCH v2 1/7] i2c: omap: no need to access platform_device
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
PM callbacks pass our device pointer as argument
and we don't need to access the platform_device
just to dereference that down to dev->drvdata.
instead, just use dev_get_drvdata() directly.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index db31eae..c07d9c4 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1239,8 +1239,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_RUNTIME
static int omap_i2c_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+ struct omap_i2c_dev *_dev = dev_get_drvdata(dev);
u16 iv;
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
@@ -1261,8 +1260,7 @@ static int omap_i2c_runtime_suspend(struct device *dev)
static int omap_i2c_runtime_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+ struct omap_i2c_dev *_dev = dev_get_drvdata(dev);
if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
--
1.8.0
^ permalink raw reply related
* [PATCH v2 2/7] i2c: omap: reorder exit path of omap_i2c_xfer_msg()
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
just a cleanup patch trying to make exit path
more straightforward. No changes otherwise.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index c07d9c4..bea0277 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -505,6 +505,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
{
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
unsigned long timeout;
+ int ret;
u16 w;
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -582,31 +583,38 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
dev->buf_len = 0;
if (timeout == 0) {
dev_err(dev->dev, "controller timed out\n");
- omap_i2c_init(dev);
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ goto err_i2c_init;
}
- if (likely(!dev->cmd_err))
- return 0;
-
/* We have an error */
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
OMAP_I2C_STAT_XUDF)) {
- omap_i2c_init(dev);
- return -EIO;
+ ret = -EIO;
+ goto err_i2c_init;
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
+
if (stop) {
w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
w |= OMAP_I2C_CON_STP;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
}
- return -EREMOTEIO;
+
+ ret = -EREMOTEIO;
+ goto err;
}
- return -EIO;
+
+ return 0;
+
+err_i2c_init:
+ omap_i2c_init(dev);
+
+err:
+ return ret;
}
--
1.8.0
^ permalink raw reply related
* [PATCH v2 3/7] i2c: omap: also complete() when stat becomes zero
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
In case we loop on IRQ handler until stat is
finally zero, we would end up in a situation
where all I2C transfers would misteriously
timeout because we were not calling complete()
in that situation.
Fix the issue by moving omap_i2c_complete_cmd()
call inside the 'out' label.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index bea0277..b004126 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1021,9 +1021,8 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
}
} while (stat);
- omap_i2c_complete_cmd(dev, err);
-
out:
+ omap_i2c_complete_cmd(dev, err);
spin_unlock_irqrestore(&dev->lock, flags);
return IRQ_HANDLED;
--
1.8.0
^ permalink raw reply related
* [PATCH v2 4/7] i2c: omap: in case of VERSION_2 read IRQSTATUS_RAW but write to IRQSTATUS
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
on OMAP4+ we want to read IRQSTATUS_RAW register,
instead of IRQSTATUS. The reason being that IRQSTATUS
will only contain the bits which were enabled on
IRQENABLE_SET and that will break when we need to
poll for a certain bit which wasn't enabled as an
IRQ source.
One such case is after we finish converting to
deferred stop bit, we will have to poll for ARDY
bit before returning control for the client driver
in order to prevent us from trying to start a
transfer on a bus which is already busy.
Note, however, that omap-i2c.c needs a big rework
on register definition and register access. Such
work will be done in a separate series of patches.
Cc: Benoit Cousson <b-cousson@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index b004126..20f9ad6 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -271,8 +271,18 @@ static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
{
- return __raw_readw(i2c_dev->base +
+ /* if we are OMAP_I2C_IP_VERSION_2, we need to read from
+ * IRQSTATUS_RAW, but write to IRQSTATUS
+ */
+ if ((i2c_dev->dtrev == OMAP_I2C_IP_VERSION_2) &&
+ (reg == OMAP_I2C_STAT_REG)) {
+ return __raw_readw(i2c_dev->base +
+ ((i2c_dev->regs[reg] - 0x04)
+ << i2c_dev->reg_shift));
+ } else {
+ return __raw_readw(i2c_dev->base +
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
+ }
}
static int omap_i2c_init(struct omap_i2c_dev *dev)
--
1.8.0
^ permalink raw reply related
* [PATCH v2 5/7] i2c: omap: wait for transfer completion before sending STP bit
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
Later patches will come adding support for
reporting amount of bytes transferred so that
client drivers can count how many bytes are
left to transfer.
This is useful mostly in case of NACKs when
client driver wants to know exactly which
byte got NACKed so it doesn't have to resend
all bytes again.
In order to make that work with OMAP's I2C
controller, we need to prevent sending STP
bit until message is transferred. The reason
behind that is because OMAP_I2C_CNT_REG gets
reset to original value after STP bit is
shifted through I2C_SDA line and that would
prevent us from reading the correct number of
bytes left to transfer.
The full programming model suggested by IP
owner was the following:
- start I2C transfer (without STP bit)
- upon completion or NACK, read I2C_CNT register
- write STP bit to I2C_CON register
- wait for ARDY bit
With this patch we're implementing all steps
except step #2 which will come in a later
patch adding such support.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 89 ++++++++++++++++---------------------------
1 file changed, 33 insertions(+), 56 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 20f9ad6..699fa12 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -438,9 +438,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
/* Enable interrupts */
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
- OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
- OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
- (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
+ OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) |
+ ((dev->fifo_size) ? (OMAP_I2C_IE_RDR |
+ OMAP_I2C_IE_XDR) : 0);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
dev->pscstate = psc;
@@ -470,6 +470,22 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
return 0;
}
+static int omap_i2c_wait_for_ardy(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_ARDY)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for access ready\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(800, 1200);
+ }
+
+ return 0;
+}
+
static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
{
u16 buf;
@@ -515,7 +531,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
{
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
unsigned long timeout;
- int ret;
+ int ret = 0;
u16 w;
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -556,35 +572,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (!(msg->flags & I2C_M_RD))
w |= OMAP_I2C_CON_TRX;
- if (!dev->b_hw && stop)
- w |= OMAP_I2C_CON_STP;
-
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
/*
- * Don't write stt and stp together on some hardware.
- */
- if (dev->b_hw && stop) {
- unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
- u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- while (con & OMAP_I2C_CON_STT) {
- con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
-
- /* Let the user know if i2c is in a bad state */
- if (time_after(jiffies, delay)) {
- dev_err(dev->dev, "controller timed out "
- "waiting for start condition to finish\n");
- return -ETIMEDOUT;
- }
- cpu_relax();
- }
-
- w |= OMAP_I2C_CON_STP;
- w &= ~OMAP_I2C_CON_STT;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
-
- /*
* REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it.
*/
@@ -594,36 +584,36 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (timeout == 0) {
dev_err(dev->dev, "controller timed out\n");
ret = -ETIMEDOUT;
- goto err_i2c_init;
+ omap_i2c_init(dev);
+ goto out;
}
/* We have an error */
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
OMAP_I2C_STAT_XUDF)) {
ret = -EIO;
- goto err_i2c_init;
+ omap_i2c_init(dev);
+ goto out;
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
- if (stop) {
- w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- w |= OMAP_I2C_CON_STP;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
-
ret = -EREMOTEIO;
- goto err;
+ omap_i2c_init(dev);
}
- return 0;
+out:
-err_i2c_init:
- omap_i2c_init(dev);
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ ret = omap_i2c_wait_for_ardy(dev);
+ }
-err:
return ret;
}
@@ -947,19 +937,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
break;
}
- /*
- * ProDB0017052: Clear ARDY bit twice
- */
- if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
- OMAP_I2C_STAT_AL)) {
- omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
- OMAP_I2C_STAT_RDR |
- OMAP_I2C_STAT_XRDY |
- OMAP_I2C_STAT_XDR |
- OMAP_I2C_STAT_ARDY));
- break;
- }
-
if (stat & OMAP_I2C_STAT_RDR) {
u8 num_bytes = 1;
--
1.8.0
^ permalink raw reply related
* [PATCH v2 6/7] i2c: add 'transferred' field to struct i2c_msg
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
From: Shubhrajyoti D <shubhrajyoti@ti.com>
In case of a NACK, it's wise to tell our clients
drivers about how many bytes were actually transferred.
Support this by adding an extra field to the struct
i2c_msg which gets incremented the amount of bytes
actually transferred.
Signed-off-by: Shubhrajyoti D <shubhrajyoti@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
include/uapi/linux/i2c.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
index 0e949cb..4b35c9b 100644
--- a/include/uapi/linux/i2c.h
+++ b/include/uapi/linux/i2c.h
@@ -77,6 +77,7 @@ struct i2c_msg {
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
+ __u16 transferred; /* actual bytes transferred */
__u8 *buf; /* pointer to msg data */
};
--
1.8.0
^ permalink raw reply related
* [PATCH v2 7/7] i2c: omap: implement handling for 'transferred' bytes
From: Felipe Balbi @ 2012-10-25 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-1-git-send-email-balbi@ti.com>
this is important in cases where client driver
wants to know how many bytes were actually
transferred.
There is one trick here: if transfer is completed,
meaning I2C_CNT reaches zero, then ARDY will be
asserted to let SW know that it can program a
new transfer.
When ARDY is asserted, I2C_CNT is reset to the
original value (msg->len), which means that
for a successful message, msg->transferred = msg->len
and we don't need to spend time with a register
read.
In case of NACK condition, however, I2C_CNT will
remain with the end value which is the amount of
data transferred until NACK condition found on the
bus inclusive. In this situation, msg->transferred
needs to be initialized with:
msg->len - read(I2C_CNT) - 1;
This patch implements exactly that handling.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 699fa12..d268e92 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -588,6 +588,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
goto out;
}
+ msg->transferred = msg->len;
+ wmb();
+
/* We have an error */
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
OMAP_I2C_STAT_XUDF)) {
@@ -597,6 +600,15 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ /* In case of a NACK, we need to check how many bytes we
+ * actually transferred, so we can tell our client driver about
+ * it.
+ *
+ * Let's check it here and overwrite msg->transferred.
+ */
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CNT_REG);
+ msg->transferred = msg->len - w - 1;
+
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
--
1.8.0
^ permalink raw reply related
* [PATCHv3] ARM: Sort exception table at compile time
From: Will Deacon @ 2012-10-25 12:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351125882-13046-1-git-send-email-sboyd@codeaurora.org>
On Thu, Oct 25, 2012 at 01:44:42AM +0100, Stephen Boyd wrote:
> Add the ARM machine identifier to sortextable and select the
> config option so that we can sort the exception table at compile
> time. sortextable relies on a section named __ex_table existing
> in the vmlinux, but ARM's linker script places the exception
> table in the data section. Give the exception table its own
> section so that sortextable can find it.
>
> This allows us to skip the sorting step during boot.
>
> Cc: David Daney <david.daney@cavium.com>
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
Just had a play with this for my A15 platform and it seems to work fine when
targetting either ARM or Thumb-2 kernels.
Tested-by: Will Deacon <will.deacon@arm.com>
Cheers,
Will
^ permalink raw reply
* [PATCH v2 5/7] i2c: omap: wait for transfer completion before sending STP bit
From: Felipe Balbi @ 2012-10-25 12:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-6-git-send-email-balbi@ti.com>
Hi,
On Thu, Oct 25, 2012 at 03:25:13PM +0300, Felipe Balbi wrote:
> Later patches will come adding support for
> reporting amount of bytes transferred so that
> client drivers can count how many bytes are
> left to transfer.
>
> This is useful mostly in case of NACKs when
> client driver wants to know exactly which
> byte got NACKed so it doesn't have to resend
> all bytes again.
>
> In order to make that work with OMAP's I2C
> controller, we need to prevent sending STP
> bit until message is transferred. The reason
> behind that is because OMAP_I2C_CNT_REG gets
> reset to original value after STP bit is
> shifted through I2C_SDA line and that would
> prevent us from reading the correct number of
> bytes left to transfer.
>
> The full programming model suggested by IP
> owner was the following:
>
> - start I2C transfer (without STP bit)
> - upon completion or NACK, read I2C_CNT register
> - write STP bit to I2C_CON register
> - wait for ARDY bit
>
> With this patch we're implementing all steps
> except step #2 which will come in a later
> patch adding such support.
>
> Signed-off-by: Felipe Balbi <balbi@ti.com>
> ---
> drivers/i2c/busses/i2c-omap.c | 89 ++++++++++++++++---------------------------
> 1 file changed, 33 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index 20f9ad6..699fa12 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -438,9 +438,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
>
> /* Enable interrupts */
> dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
> - OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
> - OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
> - (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
> + OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) |
> + ((dev->fifo_size) ? (OMAP_I2C_IE_RDR |
> + OMAP_I2C_IE_XDR) : 0);
> omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
> if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
> dev->pscstate = psc;
> @@ -470,6 +470,22 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
> return 0;
> }
>
> +static int omap_i2c_wait_for_ardy(struct omap_i2c_dev *dev)
> +{
> + unsigned long timeout;
> +
> + timeout = jiffies + OMAP_I2C_TIMEOUT;
> + while (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_ARDY)) {
> + if (time_after(jiffies, timeout)) {
> + dev_warn(dev->dev, "timeout waiting for access ready\n");
> + return -ETIMEDOUT;
> + }
> + usleep_range(800, 1200);
> + }
> +
> + return 0;
> +}
> +
> static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
> {
> u16 buf;
> @@ -515,7 +531,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> {
> struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
> unsigned long timeout;
> - int ret;
> + int ret = 0;
> u16 w;
>
> dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
> @@ -556,35 +572,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> if (!(msg->flags & I2C_M_RD))
> w |= OMAP_I2C_CON_TRX;
>
> - if (!dev->b_hw && stop)
> - w |= OMAP_I2C_CON_STP;
> -
> omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
>
> /*
> - * Don't write stt and stp together on some hardware.
> - */
> - if (dev->b_hw && stop) {
> - unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
> - u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> - while (con & OMAP_I2C_CON_STT) {
> - con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> -
> - /* Let the user know if i2c is in a bad state */
> - if (time_after(jiffies, delay)) {
> - dev_err(dev->dev, "controller timed out "
> - "waiting for start condition to finish\n");
> - return -ETIMEDOUT;
> - }
> - cpu_relax();
> - }
> -
> - w |= OMAP_I2C_CON_STP;
> - w &= ~OMAP_I2C_CON_STT;
> - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> - }
> -
> - /*
> * REVISIT: We should abort the transfer on signals, but the bus goes
> * into arbitration and we're currently unable to recover from it.
> */
> @@ -594,36 +584,36 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> if (timeout == 0) {
> dev_err(dev->dev, "controller timed out\n");
> ret = -ETIMEDOUT;
> - goto err_i2c_init;
> + omap_i2c_init(dev);
> + goto out;
> }
>
> /* We have an error */
> if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
> OMAP_I2C_STAT_XUDF)) {
> ret = -EIO;
> - goto err_i2c_init;
> + omap_i2c_init(dev);
> + goto out;
> }
>
> if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
> if (msg->flags & I2C_M_IGNORE_NAK)
> return 0;
>
> - if (stop) {
> - w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> - w |= OMAP_I2C_CON_STP;
> - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> - }
> -
> ret = -EREMOTEIO;
> - goto err;
> + omap_i2c_init(dev);
this is wrong. I will resend this patch alone. My bad.
--
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121025/d51dc1cc/attachment.sig>
^ permalink raw reply
* [PATCH 2/6] pinctrl: Update clock handling for the pinctrl-nomadik GPIO driver
From: Linus Walleij @ 2012-10-25 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPDyKFromkv_VYgiQsERR=PbrwYqgux=teF_HSZxCtk2BCsk1A@mail.gmail.com>
On Thu, Oct 25, 2012 at 11:29 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> Depending on clock type, a clk_disable is actually not going to "gate"
> the clock, that might happen only in unprepare. This depends on if the
> clock is a fast or slow clock.
Hm thats interesting. Now I need to drill down into this.
So looking at it in this case:
clk_disable() from the GPIO block of the pin controller will
hit "gpio.0", "gpio.1" etc in drivers/clk/ux500/u8500_clk.c.
These are PRCC (Programmable Clock Controller) clocks
registered using clk_reg_prcc_pclk() from clk-prcc.c.
pclk:s are using the clk_prcc_pclk_ops and these point to
clk_prcc_pclk_enable()/clk_prcc_pclk_disable() for
enable/disable respectively.
These will just write a PRCC register.
And prepare() and unprepare() are not implemented for
this clock.
So far we can conclude that clk_enable()/disable()
will indeed achieve the desired effect of gating the
clock to the GPIO block per se, so we are saving
some power for sure.
However the prepare()/unprepare() calls will of course
also accumulate upwards and in e.g. the example of
"gpio.0" and "gpio.1" the parent is "per1clk" which is the
clock for the entire peripheral group.
(At this point I can stick in a reminder of the idea to
restructure the device tree in peripheral groups, because
that exercise will certainly pay off the day we try to encode
clocks in the device tree, I think the point can be clearly
seen as we proceed...)
This "per1clk" is registered using clk_req_prcmu_gate()
from clk-prcmu.c.
Looking at that clock type we find it's a plain software
dummy for the clk_enable()/clk_disable() path.
The real action is happening in the prepare()/unprepare()
path.
So to be able to shut down the entire peripheral cluster,
indeed both functions need to be called.
So in accordance with this we can see that the patch
should be applied, in some form.
However it is not removing the initial clk_prepare()
so the entire patch will be pointless, the prepare count
will currently always be > 0.
I'll mangle Lee's patch a bit, hold on..
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH V3 1/5] ARM: dts: OMAP: Add timer nodes
From: Jon Hunter @ 2012-10-25 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50892E27.7070102@ti.com>
On 10/25/2012 07:18 AM, Jon Hunter wrote:
...
>> @@ -113,6 +114,9 @@ static int omap_timer_interrupt_test(struct omap_dm_timer *gptimer)
>>
>> irq_data.gptimer = gptimer;
>> init_completion(&irq_data.complete);
>> +
>> + omap_dm_timer_enable(gptimer);
>> +
>> omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
>> omap_dm_timer_set_load_start(gptimer, 0, 0xffffff00);
>>
>> @@ -128,6 +132,8 @@ static int omap_timer_interrupt_test(struct omap_dm_timer *gptimer)
>>
>> omap_dm_timer_stop(gptimer);
>> omap_dm_timer_set_int_enable(gptimer, 0);
>> + omap_dm_timer_disable(gptimer);
>> +
>
> Hmmm ... I am wondering if there is another bug lingering in the dmtimer
> driver. Ideally, the context should be preserved by the driver.
Looking at omap_dm_timer_set_load_start() we have the following code to
restore context ...
if (!(timer->capability & OMAP_TIMER_ALWON)) {
if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
timer->ctx_loss_count)
omap_timer_restore_context(timer);
}
Can you see if this is getting called for AM33xx for the failing timers?
If not then it would suggest that we are not detecting context loss
correctly and not restoring the context. With the above context restore
code we should not need those extra omap_dm_timer_enable/disable calls.
Cheers
Jon
^ permalink raw reply
* [PATCH v3 5/7] i2c: omap: wait for transfer completion before sending STP bit
From: Felipe Balbi @ 2012-10-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-6-git-send-email-balbi@ti.com>
Later patches will come adding support for
reporting amount of bytes transferred so that
client drivers can count how many bytes are
left to transfer.
This is useful mostly in case of NACKs when
client driver wants to know exactly which
byte got NACKed so it doesn't have to resend
all bytes again.
In order to make that work with OMAP's I2C
controller, we need to prevent sending STP
bit until message is transferred. The reason
behind that is because OMAP_I2C_CNT_REG gets
reset to original value after STP bit is
shifted through I2C_SDA line and that would
prevent us from reading the correct number of
bytes left to transfer.
The full programming model suggested by IP
owner was the following:
- start I2C transfer (without STP bit)
- upon completion or NACK, read I2C_CNT register
- write STP bit to I2C_CON register
- wait for ARDY bit
With this patch we're implementing all steps
except step #2 which will come in a later
patch adding such support.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
Changes since v2:
- remove unnecessary omap_i2c_init() which was added during a rebase.
drivers/i2c/busses/i2c-omap.c | 88 ++++++++++++++++---------------------------
1 file changed, 32 insertions(+), 56 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 20f9ad6..726b916 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -438,9 +438,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
/* Enable interrupts */
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
- OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
- OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
- (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
+ OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) |
+ ((dev->fifo_size) ? (OMAP_I2C_IE_RDR |
+ OMAP_I2C_IE_XDR) : 0);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
dev->pscstate = psc;
@@ -470,6 +470,22 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
return 0;
}
+static int omap_i2c_wait_for_ardy(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_ARDY)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for access ready\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(800, 1200);
+ }
+
+ return 0;
+}
+
static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
{
u16 buf;
@@ -515,7 +531,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
{
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
unsigned long timeout;
- int ret;
+ int ret = 0;
u16 w;
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -556,35 +572,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (!(msg->flags & I2C_M_RD))
w |= OMAP_I2C_CON_TRX;
- if (!dev->b_hw && stop)
- w |= OMAP_I2C_CON_STP;
-
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
/*
- * Don't write stt and stp together on some hardware.
- */
- if (dev->b_hw && stop) {
- unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
- u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- while (con & OMAP_I2C_CON_STT) {
- con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
-
- /* Let the user know if i2c is in a bad state */
- if (time_after(jiffies, delay)) {
- dev_err(dev->dev, "controller timed out "
- "waiting for start condition to finish\n");
- return -ETIMEDOUT;
- }
- cpu_relax();
- }
-
- w |= OMAP_I2C_CON_STP;
- w &= ~OMAP_I2C_CON_STT;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
-
- /*
* REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it.
*/
@@ -594,36 +584,35 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (timeout == 0) {
dev_err(dev->dev, "controller timed out\n");
ret = -ETIMEDOUT;
- goto err_i2c_init;
+ omap_i2c_init(dev);
+ goto out;
}
/* We have an error */
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
OMAP_I2C_STAT_XUDF)) {
ret = -EIO;
- goto err_i2c_init;
+ omap_i2c_init(dev);
+ goto out;
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
- if (stop) {
- w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- w |= OMAP_I2C_CON_STP;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
-
ret = -EREMOTEIO;
- goto err;
}
- return 0;
+out:
-err_i2c_init:
- omap_i2c_init(dev);
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ ret = omap_i2c_wait_for_ardy(dev);
+ }
-err:
return ret;
}
@@ -947,19 +936,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
break;
}
- /*
- * ProDB0017052: Clear ARDY bit twice
- */
- if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
- OMAP_I2C_STAT_AL)) {
- omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
- OMAP_I2C_STAT_RDR |
- OMAP_I2C_STAT_XRDY |
- OMAP_I2C_STAT_XDR |
- OMAP_I2C_STAT_ARDY));
- break;
- }
-
if (stat & OMAP_I2C_STAT_RDR) {
u8 num_bytes = 1;
--
1.8.0
^ permalink raw reply related
* [PATCH] arm: mvebu: move irq controller driver in drivers/irqchip/
From: Thomas Petazzoni @ 2012-10-25 12:35 UTC (permalink / raw)
To: linux-arm-kernel
The new support for the ARM BCM2835 SoC has introduced the
drivers/irqchip/ directory for IRQ controller drivers. So let's
conform to this good new approach, and move the IRQ controller driver
for Marvell Armada 370/XP in this directory.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/mach-mvebu/Makefile | 2 +-
arch/arm/mach-mvebu/armada-370-xp.c | 1 +
arch/arm/mach-mvebu/common.h | 3 ---
drivers/irqchip/Makefile | 1 +
.../irqchip}/irq-armada-370-xp.c | 0
include/linux/irqchip/armada-370-xp.h | 19 +++++++++++++++++++
6 files changed, 22 insertions(+), 4 deletions(-)
rename {arch/arm/mach-mvebu => drivers/irqchip}/irq-armada-370-xp.c (100%)
create mode 100644 include/linux/irqchip/armada-370-xp.h
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 57f996b..7f4e9f4 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -2,4 +2,4 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
-I$(srctree)/arch/arm/plat-orion/include
obj-y += system-controller.o
-obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o
+obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o addr-map.o
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index 49d7915..1c0021d 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/time-armada-370-xp.h>
+#include <linux/irqchip/armada-370-xp.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 02f89ea..f0eaa21 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -17,7 +17,4 @@
void mvebu_restart(char mode, const char *cmd);
-void armada_370_xp_init_irq(void);
-void armada_370_xp_handle_irq(struct pt_regs *regs);
-
#endif
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 054321d..af0412c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
+obj-$(CONFIG_MACH_ARMADA_370_XP) += irq-armada-370-xp.o
diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
similarity index 100%
rename from arch/arm/mach-mvebu/irq-armada-370-xp.c
rename to drivers/irqchip/irq-armada-370-xp.c
diff --git a/include/linux/irqchip/armada-370-xp.h b/include/linux/irqchip/armada-370-xp.h
new file mode 100644
index 0000000..78876c2
--- /dev/null
+++ b/include/linux/irqchip/armada-370-xp.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __LINUX_IRQCHIP_ARMADA_370_XP_H_
+#define __LINUX_IRQCHIP_ARMADA_370_XP_H_
+
+#include <asm/exception.h>
+
+void armada_370_xp_init_irq(void);
+void armada_370_xp_handle_irq(struct pt_regs *regs);
+
+#endif
--
1.7.9.5
^ permalink raw reply related
* Possible regression in arm/io.h
From: Mikael Pettersson @ 2012-10-25 12:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121025111705.GD11267@mudshark.cambridge.arm.com>
Will Deacon writes:
> On Thu, Oct 25, 2012 at 07:55:22AM +0100, Artem Bityutskiy wrote:
> > On Wed, 2012-10-24 at 11:52 +0100, Will Deacon wrote:
> > > (a) Understand what has changed in GCC to cause this error to start
> > > cropping up.
> >
> > This is about already quite old gcc 4.6.3, which I use for about 4 last
> > kernel releases already. So it is only the kernel that changed.
>
> Looks like it's broken with gcc 4.7 too, so it might be that it's never
> worked. The problem seems to be that offsettable addresses are assumed by
> GCC to have a 12-bit immediate range, which isn't true for half- and double-
> work accessors, so GAS barfs when presented with the final (invalid) code.
...
> Unfortunately, GCC doesn't give us another constraint
> that we can use for this, so I think we just have to grin and bear it.
Please file a GCC bugzilla entry with an enhancement request to support
ARM constraint letters for other immediate sizes than 12 (and list which
sizes are missing).
^ permalink raw reply
* [PATCH v2 3/7] i2c: omap: also complete() when stat becomes zero
From: Felipe Balbi @ 2012-10-25 12:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <508933E4.7070608@ti.com>
Hi,
On Thu, Oct 25, 2012 at 06:13:16PM +0530, Santosh Shilimkar wrote:
> On Thursday 25 October 2012 05:55 PM, Felipe Balbi wrote:
> >In case we loop on IRQ handler until stat is
> >finally zero, we would end up in a situation
> >where all I2C transfers would misteriously
> >timeout because we were not calling complete()
> >in that situation.
> >
> >Fix the issue by moving omap_i2c_complete_cmd()
> >call inside the 'out' label.
> >
> >Signed-off-by: Felipe Balbi <balbi@ti.com>
> >---
> Looks fine. Have you hit this issue in any corner case ?
in fact, yes. With a difficult to reproduce situation with drv2665 (one
of TI's piezo drivers) I saw that I was missing the ack and all
transfers were timing out ;-)
--
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121025/53259a9f/attachment.sig>
^ permalink raw reply
* [PATCH v2 2/7] i2c: omap: reorder exit path of omap_i2c_xfer_msg()
From: Felipe Balbi @ 2012-10-25 12:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50893398.6070004@ti.com>
Hi,
On Thu, Oct 25, 2012 at 06:12:00PM +0530, Santosh Shilimkar wrote:
> On Thursday 25 October 2012 05:55 PM, Felipe Balbi wrote:
> >just a cleanup patch trying to make exit path
> >more straightforward. No changes otherwise.
> >
> >Signed-off-by: Felipe Balbi <balbi@ti.com>
> >---
> > drivers/i2c/busses/i2c-omap.c | 26 +++++++++++++++++---------
> > 1 file changed, 17 insertions(+), 9 deletions(-)
> >
> >diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> >index c07d9c4..bea0277 100644
> >--- a/drivers/i2c/busses/i2c-omap.c
> >+++ b/drivers/i2c/busses/i2c-omap.c
> >@@ -505,6 +505,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> > {
> > struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
> > unsigned long timeout;
> >+ int ret;
> You might want to initialize the error value to avoid return 0. Compiler
> might be already cribbing for it
>
> > u16 w;
> >
> > dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
> >@@ -582,31 +583,38 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> > dev->buf_len = 0;
> > if (timeout == 0) {
> > dev_err(dev->dev, "controller timed out\n");
> >- omap_i2c_init(dev);
> >- return -ETIMEDOUT;
> >+ ret = -ETIMEDOUT;
> >+ goto err_i2c_init;
> > }
> >
> >- if (likely(!dev->cmd_err))
> >- return 0;
> >-
> Have you have drooped this check completely ?
yes, the idea is to have a single exit point, so all checks below would
be executed.
> > /* We have an error */
> > if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
> > OMAP_I2C_STAT_XUDF)) {
> >- omap_i2c_init(dev);
> >- return -EIO;
> >+ ret = -EIO;
> >+ goto err_i2c_init;
> > }
> >
> > if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
> > if (msg->flags & I2C_M_IGNORE_NAK)
> > return 0;
> >+
> > if (stop) {
> > w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> > w |= OMAP_I2C_CON_STP;
> > omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> > }
> >- return -EREMOTEIO;
> >+
> >+ ret = -EREMOTEIO;
> >+ goto err;
> > }
> >- return -EIO;
> >+
> >+ return 0;
> With initialized value you can use
> return ret;
hmm, I guess I did that on a follow up patch where I grouped the stop
handling.
--
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121025/ee35f97f/attachment-0001.sig>
^ permalink raw reply
* [PATCH 2/6] pinctrl: Update clock handling for the pinctrl-nomadik GPIO driver
From: Linus Walleij @ 2012-10-25 12:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351089926-32161-3-git-send-email-lee.jones@linaro.org>
On Wed, Oct 24, 2012 at 4:45 PM, Lee Jones <lee.jones@linaro.org> wrote:
> The clock framework has changed somewhat and it's now better to
> invoke clock_prepare_enable() and clk_disable_unprepare() rather
> than the legacy clk_enable() and clk_disable() calls. This patch
> converts the Nomadik Pin Control driver to the new framework.
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
I was convinced that this is a good change but no regression,
so applied to the devel branch for 3.8.
I also removed the initial clk_prepare() so the reference count
may actually go down to 0 for the GPIO block and the peripheral
cluster eventually gets relaxed.
Thanks!
Linus Walleij
^ permalink raw reply
* [PATCH] ARM: decompressor: clear SCTLR.A bit for v7 cores
From: Rob Herring @ 2012-10-25 12:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121025093411.GA32662@sig21.net>
On 10/25/2012 04:34 AM, Johannes Stezenbach wrote:
> On Thu, Oct 11, 2012 at 07:43:22AM -0500, Rob Herring wrote:
>>
>> With recent compilers and move to generic unaligned.h in commit d25c881
>> (ARM: 7493/1: use generic unaligned.h), unaligned accesses will be used
>> by the LZO decompressor on v7 cores. So we need to make sure unaligned
>> accesses are allowed by clearing the SCTLR A bit.
>
> I just read this in http://gcc.gnu.org/gcc-4.7/changes.html:
>
> On ARM, when compiling for ARMv6 (but not ARMv6-M), ARMv7-A, ARMv7-R, or
> ARMv7-M, the new option -munaligned-access is active by default, which for
> some source codes generates code that accesses memory on unaligned addresses.
> This will require the kernel of those systems to enable such accesses
> (controlled by CP15 register c1, refer to ARM documentation). Alternatively
> or for compatibility with kernels where unaligned accesses are not supported,
> all code has to be compiled with -mno-unaligned-access. Linux/ARM in official
> releases has automatically and unconditionally supported unaligned accesses
> as emitted by GCC due to this option being active, since Linux version 2.6.28.
I don't think there is such a thing as ARMv6-M.
> My understanding is that gcc, using the same generic unaligned.h
> source code, will generate code for ARMv6 and ARMv7 that uses
> unaligned access, while for ARMv5 and older it won't. So it seems
> gcc requires Linux to clear SCTLR.A and set SCTLR.U for ARMv6+.
>
> Or add -mno-unaligned-access.
>
> Is my understanding correct?
>
>> While v6 can support unaligned accesses, it is optional and current
>> compilers won't emit unaligned accesses. So we don't clear the A bit for
>> v6.
>
> not true according to the gcc changes page
What are you going to believe: documentation or what the compiler
emitted? At least for ubuntu/linaro 4.6.3 which has the unaligned access
support backported and 4.7.2, unaligned accesses are emitted for v7
only. I guess default here means it is the default unless you change the
default in your build of gcc.
If we are going to do combined v6k and v7 kernels, then it would be nice
if we could get the compiler to emit unaligned accesses (assuming we
agree we can require that for v6).
Rob
^ permalink raw reply
* [PATCH v2 1/7] i2c: omap: no need to access platform_device
From: Santosh Shilimkar @ 2012-10-25 12:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-2-git-send-email-balbi@ti.com>
On Thursday 25 October 2012 05:55 PM, Felipe Balbi wrote:
> PM callbacks pass our device pointer as argument
> and we don't need to access the platform_device
> just to dereference that down to dev->drvdata.
>
> instead, just use dev_get_drvdata() directly.
>
> Signed-off-by: Felipe Balbi <balbi@ti.com>
> ---
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
^ permalink raw reply
* [PATCH v2 2/7] i2c: omap: reorder exit path of omap_i2c_xfer_msg()
From: Santosh Shilimkar @ 2012-10-25 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-3-git-send-email-balbi@ti.com>
On Thursday 25 October 2012 05:55 PM, Felipe Balbi wrote:
> just a cleanup patch trying to make exit path
> more straightforward. No changes otherwise.
>
> Signed-off-by: Felipe Balbi <balbi@ti.com>
> ---
> drivers/i2c/busses/i2c-omap.c | 26 +++++++++++++++++---------
> 1 file changed, 17 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index c07d9c4..bea0277 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -505,6 +505,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> {
> struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
> unsigned long timeout;
> + int ret;
You might want to initialize the error value to avoid return 0. Compiler
might be already cribbing for it
> u16 w;
>
> dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
> @@ -582,31 +583,38 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> dev->buf_len = 0;
> if (timeout == 0) {
> dev_err(dev->dev, "controller timed out\n");
> - omap_i2c_init(dev);
> - return -ETIMEDOUT;
> + ret = -ETIMEDOUT;
> + goto err_i2c_init;
> }
>
> - if (likely(!dev->cmd_err))
> - return 0;
> -
Have you have drooped this check completely ?
> /* We have an error */
> if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
> OMAP_I2C_STAT_XUDF)) {
> - omap_i2c_init(dev);
> - return -EIO;
> + ret = -EIO;
> + goto err_i2c_init;
> }
>
> if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
> if (msg->flags & I2C_M_IGNORE_NAK)
> return 0;
> +
> if (stop) {
> w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> w |= OMAP_I2C_CON_STP;
> omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> }
> - return -EREMOTEIO;
> +
> + ret = -EREMOTEIO;
> + goto err;
> }
> - return -EIO;
> +
> + return 0;
With initialized value you can use
return ret;
Regards
Santosh
^ permalink raw reply
* [PATCH v2 3/7] i2c: omap: also complete() when stat becomes zero
From: Santosh Shilimkar @ 2012-10-25 12:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351167915-15079-4-git-send-email-balbi@ti.com>
On Thursday 25 October 2012 05:55 PM, Felipe Balbi wrote:
> In case we loop on IRQ handler until stat is
> finally zero, we would end up in a situation
> where all I2C transfers would misteriously
> timeout because we were not calling complete()
> in that situation.
>
> Fix the issue by moving omap_i2c_complete_cmd()
> call inside the 'out' label.
>
> Signed-off-by: Felipe Balbi <balbi@ti.com>
> ---
Looks fine. Have you hit this issue in any corner case ?
Regards
santosh
^ permalink raw reply
* [PATCH v2 4/7] i2c: omap: in case of VERSION_2 read IRQSTATUS_RAW but write to IRQSTATUS
From: Felipe Balbi @ 2012-10-25 12:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50893665.60604@ti.com>
Hi,
On Thu, Oct 25, 2012 at 06:23:57PM +0530, Santosh Shilimkar wrote:
> On Thursday 25 October 2012 05:55 PM, Felipe Balbi wrote:
> >on OMAP4+ we want to read IRQSTATUS_RAW register,
> >instead of IRQSTATUS. The reason being that IRQSTATUS
> >will only contain the bits which were enabled on
> >IRQENABLE_SET and that will break when we need to
> >poll for a certain bit which wasn't enabled as an
> >IRQ source.
> >
> >One such case is after we finish converting to
> >deferred stop bit, we will have to poll for ARDY
> >bit before returning control for the client driver
> >in order to prevent us from trying to start a
> >transfer on a bus which is already busy.
> >
> >Note, however, that omap-i2c.c needs a big rework
> >on register definition and register access. Such
> >work will be done in a separate series of patches.
> >
> >Cc: Benoit Cousson <b-cousson@ti.com>
> >Signed-off-by: Felipe Balbi <balbi@ti.com>
> >---
> > drivers/i2c/busses/i2c-omap.c | 12 +++++++++++-
> > 1 file changed, 11 insertions(+), 1 deletion(-)
> >
> >diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> >index b004126..20f9ad6 100644
> >--- a/drivers/i2c/busses/i2c-omap.c
> >+++ b/drivers/i2c/busses/i2c-omap.c
> >@@ -271,8 +271,18 @@ static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
> >
> > static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
> > {
> >- return __raw_readw(i2c_dev->base +
> >+ /* if we are OMAP_I2C_IP_VERSION_2, we need to read from
> >+ * IRQSTATUS_RAW, but write to IRQSTATUS
> >+ */
> >+ if ((i2c_dev->dtrev == OMAP_I2C_IP_VERSION_2) &&
> >+ (reg == OMAP_I2C_STAT_REG)) {
> Doing this check on every I2C register read seems to
> expensive to me. Can you not sort this in init with some offset
> which can be 0 or non zero ? Sorry in case this is already dicussed.
could be. I didn't go that route because I'm planning a complete rewrite
of all register accesses. The way it's done today is completely broken
and already expensive (with reg_shift and different map tables and so
on).
If it's really a big of a deal, I can try to find another way, maybe
just adding omap_i2c_read_stat() and limit the version check just to
I2C_STAT reads would do it for now...
--
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121025/d7a764f7/attachment.sig>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox