From a404ad1ff593589bdd34c48ebecddada9edbfaf3 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:33:53 +0100 Subject: ARM: 6452/1: Fix checkpatch.pl issues in drivers/rtc/rtc-sa1100.c. This patch fixes checkpatch.pl issues in drivers/rtc/rtc-sa1100.c, which I will later modify. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index e4a44b641702..e19ed0f6dca0 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -39,7 +39,7 @@ #include #endif -#define RTC_DEF_DIVIDER 32768 - 1 +#define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 static unsigned long rtc_freq = 1024; @@ -61,7 +61,8 @@ static inline int rtc_periodic_alarm(struct rtc_time *tm) * Calculate the next alarm time given the requested alarm time mask * and the current time. */ -static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, + struct rtc_time *alrm) { unsigned long next_time; unsigned long now_time; @@ -178,7 +179,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) * Here we compare (match - OSCR) 8 instead of 0 -- * see comment in pxa_timer_interrupt() for explanation. */ - while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { + while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) { data += 0x100; OSSR = OSSR_M1; /* clear match on timer 1 */ OSMR1 = osmr1 + period; @@ -192,19 +193,19 @@ static int sa1100_rtc_open(struct device *dev) int ret; ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc 1Hz", dev); + "rtc 1Hz", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); goto fail_ui; } ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc Alrm", dev); + "rtc Alrm", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); goto fail_ai; } ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, - "rtc timer", dev); + "rtc timer", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); goto fail_pi; @@ -236,7 +237,7 @@ static void sa1100_rtc_release(struct device *dev) static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - switch(cmd) { + switch (cmd) { case RTC_AIE_OFF: spin_lock_irq(&sa1100_rtc_lock); RTSR &= ~RTSR_ALE; @@ -364,7 +365,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) */ if (RTTR == 0) { RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n"); + dev_warn(&pdev->dev, "warning: " + "initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ RCNR = 0; } @@ -386,7 +388,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); - if (rtc) + if (rtc) rtc_device_unregister(rtc); return 0; -- cgit v1.2.3 From fd3ee6d3421bc05ce42ee7f48071aee72051af28 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:34:47 +0100 Subject: ARM: 6453/1: sa1100: Print the value of RTSR on /proc/drivers/rtc. This patch adds a line to the output of /proc/drivers/rtc to show the value of the RTSR register. It will be used to demonstrate a nasty initialization bug that will be fixed in the sequence. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index e19ed0f6dca0..b04c8374a279 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -334,6 +334,7 @@ static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) seq_printf(seq, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); + seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR); return 0; } -- cgit v1.2.3 From 7decaa557a20f48aabef35f817ec16ef563567b0 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:35:54 +0100 Subject: ARM: 6454/1: sa1100: Fix for a nasty initialization bug in the RTSR. This patch fixes a nasty initialization condition on the RTSR register. Sometimes, bit 1 will wake up set, sometimes not. This can be seen by checking the value of the RTSR by typing '$ cat /proc/driver/rtc', which has been provided by the previous patch. If this bit is set, the command '$ cat /dev/rtc0' will lock the system in an endless interrupt routine calling loop. This patch fixes the issue both at sa1100_rtc_probe(), where it avoids a spurious interrupt from happening, and at sa1100_rtc_interrupt(), which is the robust solution, though it does not avoid the first spurious interrupt. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b04c8374a279..b0985f727078 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -117,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) rtsr = RTSR; /* clear interrupt sources */ RTSR = 0; - RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + /* Fix for a nasty initialization problem the in SA11xx RTSR register. + * See also the comments in sa1100_rtc_probe(). */ + if (rtsr & (RTSR_ALE | RTSR_HZE)) { + /* This is the original code, before there was the if test + * above. This code does not clear interrupts that were not + * enabled. */ + RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + } else { + /* For some reason, it is possible to enter this routine + * without interruptions enabled, it has been tested with + * several units (Bug in SA11xx chip?). + * + * This situation leads to an infinite "loop" of interrupt + * routine calling and as a result the processor seems to + * lock on its first call to open(). */ + RTSR = RTSR_AL | RTSR_HZ; + } /* clear alarm interrupt if it has occurred */ if (rtsr & RTSR_AL) @@ -382,6 +398,30 @@ static int sa1100_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + /* Fix for a nasty initialization problem the in SA11xx RTSR register. + * See also the comments in sa1100_rtc_interrupt(). + * + * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an + * interrupt pending, even though interrupts were never enabled. + * In this case, this bit it must be reset before enabling + * interruptions to avoid a nonexistent interrupt to occur. + * + * In principle, the same problem would apply to bit 0, although it has + * never been observed to happen. + * + * This issue is addressed both here and in sa1100_rtc_interrupt(). + * If the issue is not addressed here, in the times when the processor + * wakes up with the bit set there will be one spurious interrupt. + * + * The issue is also dealt with in sa1100_rtc_interrupt() to be on the + * safe side, once the condition that lead to this strange + * initialization is unknown and could in principle happen during + * normal processing. + * + * Notice that clearing bit 1 and 0 is accomplished by writting ONES to + * the corresponding bits in RTSR. */ + RTSR = RTSR_AL | RTSR_HZ; + return 0; } -- cgit v1.2.3 From d2ccb52d88dcb7eb3539d0e0c77a7028b8d46037 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Thu, 16 Dec 2010 21:31:32 +0100 Subject: ARM: 6455/2: Better use of the RTC framework for sa11xx. This patch uses the RTC framework to treat some common ioctl. In particular, it fixes the behaviour of rtc_irq_set_freq(), which did not work as expected because the timer was not beeing retriggered. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 98 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b0985f727078..88ea52b8647a 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -42,7 +42,7 @@ #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 -static unsigned long rtc_freq = 1024; +static const unsigned long RTC_FREQ = 1024; static unsigned long timer_freq; static struct rtc_time rtc_alarm; static DEFINE_SPINLOCK(sa1100_rtc_lock); @@ -156,8 +156,58 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int sa1100_irq_set_freq(struct device *dev, int freq) +{ + if (freq < 1 || freq > timer_freq) { + return -EINVAL; + } else { + struct rtc_device *rtc = (struct rtc_device *)dev; + + rtc->irq_freq = freq; + + return 0; + } +} + static int rtc_timer1_count; +static int sa1100_irq_set_state(struct device *dev, int enabled) +{ + spin_lock_irq(&sa1100_rtc_lock); + if (enabled) { + struct rtc_device *rtc = (struct rtc_device *)dev; + + OSMR1 = timer_freq / rtc->irq_freq + OSCR; + OIER |= OIER_E1; + rtc_timer1_count = 1; + } else { + OIER &= ~OIER_E1; + } + spin_unlock_irq(&sa1100_rtc_lock); + + return 0; +} + +static inline int sa1100_timer1_retrigger(struct rtc_device *rtc) +{ + unsigned long diff; + unsigned long period = timer_freq / rtc->irq_freq; + + spin_lock_irq(&sa1100_rtc_lock); + + do { + OSMR1 += period; + diff = OSMR1 - OSCR; + /* If OSCR > OSMR1, diff is a very large number (unsigned + * math). This means we have a lost interrupt. */ + } while (diff > period); + OIER |= OIER_E1; + + spin_unlock_irq(&sa1100_rtc_lock); + + return 0; +} + static irqreturn_t timer1_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); @@ -175,7 +225,11 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); if (rtc_timer1_count == 1) - rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2))); + rtc_timer1_count = + (rtc->irq_freq * ((1 << 30) / (timer_freq >> 2))); + + /* retrigger. */ + sa1100_timer1_retrigger(rtc); return IRQ_HANDLED; } @@ -183,8 +237,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) static int sa1100_rtc_read_callback(struct device *dev, int data) { if (data & RTC_PF) { + struct rtc_device *rtc = (struct rtc_device *)dev; + /* interpolate missed periods and set match for the next */ - unsigned long period = timer_freq / rtc_freq; + unsigned long period = timer_freq / rtc->irq_freq; unsigned long oscr = OSCR; unsigned long osmr1 = OSMR1; unsigned long missed = (oscr - osmr1)/period; @@ -207,6 +263,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) static int sa1100_rtc_open(struct device *dev) { int ret; + struct rtc_device *rtc = (struct rtc_device *)dev; ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, "rtc 1Hz", dev); @@ -226,6 +283,9 @@ static int sa1100_rtc_open(struct device *dev) dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); goto fail_pi; } + rtc->max_user_freq = RTC_FREQ; + sa1100_irq_set_freq(dev, RTC_FREQ); + return 0; fail_pi: @@ -274,25 +334,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, RTSR |= RTSR_HZE; spin_unlock_irq(&sa1100_rtc_lock); return 0; - case RTC_PIE_OFF: - spin_lock_irq(&sa1100_rtc_lock); - OIER &= ~OIER_E1; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_PIE_ON: - spin_lock_irq(&sa1100_rtc_lock); - OSMR1 = timer_freq / rtc_freq + OSCR; - OIER |= OIER_E1; - rtc_timer1_count = 1; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_IRQP_READ: - return put_user(rtc_freq, (unsigned long *)arg); - case RTC_IRQP_SET: - if (arg < 1 || arg > timer_freq) - return -EINVAL; - rtc_freq = arg; - return 0; } return -ENOIOCTLCMD; } @@ -344,12 +385,14 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { + struct rtc_device *rtc = (struct rtc_device *)dev; + seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR); seq_printf(seq, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no"); seq_printf(seq, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); - seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); + seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq); seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR); return 0; @@ -365,6 +408,8 @@ static const struct rtc_class_ops sa1100_rtc_ops = { .read_alarm = sa1100_rtc_read_alarm, .set_alarm = sa1100_rtc_set_alarm, .proc = sa1100_rtc_proc, + .irq_set_freq = sa1100_irq_set_freq, + .irq_set_state = sa1100_irq_set_state, }; static int sa1100_rtc_probe(struct platform_device *pdev) @@ -391,13 +436,18 @@ static int sa1100_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, - THIS_MODULE); + THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); platform_set_drvdata(pdev, rtc); + /* Set the irq_freq */ + /*TODO: Find out who is messing with this value after we initialize + * it here.*/ + rtc->irq_freq = RTC_FREQ; + /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). * -- cgit v1.2.3 From 17b38ebb6a32250a220d6af77293f7e3f9c62a6e Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:39:05 +0100 Subject: ARM: 6457/1: pcmcia: Fix checkpatch.pl issues in drivers/pcmcia/soc_common.c. This patch fixes checkpatch.pl issues in drivers/pcmcia/soc_common.c. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 128 +++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 689e3c02edb8..b42e129b7673 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -31,20 +31,20 @@ ======================================================================*/ -#include -#include +#include #include +#include +#include +#include #include -#include #include +#include +#include #include -#include -#include #include -#include +#include #include -#include #include #include "soc_common.h" @@ -68,7 +68,8 @@ void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func, #endif -#define to_soc_pcmcia_socket(x) container_of(x, struct soc_pcmcia_socket, socket) +#define to_soc_pcmcia_socket(x) \ + container_of(x, struct soc_pcmcia_socket, socket) static unsigned short calc_speed(unsigned short *spds, int num, unsigned short dflt) @@ -85,11 +86,15 @@ calc_speed(unsigned short *spds, int num, unsigned short dflt) return speed; } -void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing) +void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, + struct soc_pcmcia_timing *timing) { - timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); - timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); - timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); + timing->io = + calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); + timing->mem = + calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); + timing->attr = + calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); } EXPORT_SYMBOL(soc_common_pcmcia_get_timing); @@ -131,8 +136,8 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) * * Convert PCMCIA socket state to our socket configure structure. */ -static int -soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *state) +static int soc_common_pcmcia_config_skt( + struct soc_pcmcia_socket *skt, socket_state_t *state) { int ret; @@ -144,7 +149,8 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat */ if (skt->irq_state != 1 && state->io_irq) { skt->irq_state = 1; - set_irq_type(skt->socket.pci_irq, IRQ_TYPE_EDGE_FALLING); + set_irq_type(skt->socket.pci_irq, + IRQ_TYPE_EDGE_FALLING); } else if (skt->irq_state == 1 && state->io_irq == 0) { skt->irq_state = 0; set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); @@ -298,24 +304,24 @@ soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) * of power configuration, reset, &c. We also record the value of * `state' in order to regurgitate it to the PCMCIA core later. */ -static int -soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) +static int soc_common_pcmcia_set_socket( + struct pcmcia_socket *sock, socket_state_t *state) { struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); - debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n", - (state->csc_mask==0)?" ":"", - (state->csc_mask&SS_DETECT)?"DETECT ":"", - (state->csc_mask&SS_READY)?"READY ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?" ":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n", + (state->csc_mask == 0) ? " " : "", + (state->csc_mask & SS_DETECT) ? "DETECT " : "", + (state->csc_mask & SS_READY) ? "READY " : "", + (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "", + (state->csc_mask & SS_BATWARN) ? "BATWARN " : "", + (state->csc_mask & SS_STSCHG) ? "STSCHG " : "", + (state->flags == 0) ? " " : "", + (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "", + (state->flags & SS_IOCARD) ? "IOCARD " : "", + (state->flags & SS_RESET) ? "RESET " : "", + (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "", + (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "", state->Vcc, state->Vpp, state->io_irq); return soc_common_pcmcia_config_skt(skt, state); @@ -330,8 +336,8 @@ soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) * * Returns: 0 on success, -1 on error */ -static int -soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) +static int soc_common_pcmcia_set_io_map( + struct pcmcia_socket *sock, struct pccard_io_map *map) { struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); unsigned short speed = map->speed; @@ -340,14 +346,14 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m map->map, map->speed, (unsigned long long)map->start, (unsigned long long)map->stop); debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", - (map->flags&MAP_PREFETCH)?"PREFETCH ":""); + (map->flags == 0) ? "" : "", + (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", + (map->flags & MAP_16BIT) ? "16BIT " : "", + (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", + (map->flags & MAP_0WS) ? "0WS " : "", + (map->flags & MAP_WRPROT) ? "WRPROT " : "", + (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "", + (map->flags & MAP_PREFETCH) ? "PREFETCH " : ""); if (map->map >= MAX_IO_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __func__, @@ -384,8 +390,8 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m * * Returns: 0 on success, -ERRNO on error */ -static int -soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) +static int soc_common_pcmcia_set_mem_map( + struct pcmcia_socket *sock, struct pccard_mem_map *map) { struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); struct resource *res; @@ -394,14 +400,14 @@ soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map debug(skt, 2, "map %u speed %u card_start %08x\n", map->map, map->speed, map->card_start); debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_ATTRIB)?"ATTRIB ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); + (map->flags == 0) ? "" : "", + (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", + (map->flags & MAP_16BIT) ? "16BIT " : "", + (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", + (map->flags & MAP_0WS) ? "0WS " : "", + (map->flags & MAP_WRPROT) ? "WRPROT " : "", + (map->flags & MAP_ATTRIB) ? "ATTRIB " : "", + (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : ""); if (map->map >= MAX_WIN) return -EINVAL; @@ -456,8 +462,8 @@ static struct bittbl conf_bits[] = { { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, }; -static void -dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) +static void dump_bits(char **p, const char *prefix, + unsigned int val, struct bittbl *bits, int sz) { char *b = *p; int i; @@ -475,13 +481,14 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_status( + struct device *dev, struct device_attribute *attr, char *buf) { struct soc_pcmcia_socket *skt = container_of(dev, struct soc_pcmcia_socket, socket.dev); char *p = buf; - p+=sprintf(p, "slot : %d\n", skt->nr); + p += sprintf(p, "slot : %d\n", skt->nr); dump_bits(&p, "status", skt->status, status_bits, ARRAY_SIZE(status_bits)); @@ -490,12 +497,12 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, ch dump_bits(&p, "cs_flags", skt->cs_state.flags, conf_bits, ARRAY_SIZE(conf_bits)); - p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); - p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); - p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, + p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); + p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); + p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->socket.pci_irq); if (skt->ops->show_timing) - p+=skt->ops->show_timing(skt, p); + p += skt->ops->show_timing(skt, p); return p-buf; } @@ -588,7 +595,7 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) mutex_lock(&soc_pcmcia_sockets_lock); list_for_each_entry(skt, &soc_pcmcia_sockets, node) - if ( skt->ops->frequency_change ) + if (skt->ops->frequency_change) ret += skt->ops->frequency_change(skt, val, freqs); mutex_unlock(&soc_pcmcia_sockets_lock); @@ -614,7 +621,8 @@ fs_initcall(soc_pcmcia_cpufreq_register); static void soc_pcmcia_cpufreq_unregister(void) { - cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); } module_exit(soc_pcmcia_cpufreq_unregister); -- cgit v1.2.3 From fa87672ab30ce6564393778b8cbc67fc32712a30 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:41:29 +0100 Subject: ARM: 6458/1: pcmcia: Adds nanoEngine PCMCIA support. This patch adds nanoEngine PCMCIA support, with support for two sockets. In order to have a fully functional pcmcia subsystem in a BSE nanoEngine board you should carefully read this: http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/ Acked-by: Dominik Brodowski Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- arch/arm/mach-sa1100/include/mach/nanoengine.h | 30 ++++ arch/arm/mach-sa1100/nanoengine.c | 2 +- drivers/pcmcia/Makefile | 3 +- drivers/pcmcia/sa1100_generic.c | 3 + drivers/pcmcia/sa1100_generic.h | 1 + drivers/pcmcia/sa1100_nanoengine.c | 219 +++++++++++++++++++++++++ 6 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-sa1100/include/mach/nanoengine.h create mode 100644 drivers/pcmcia/sa1100_nanoengine.c (limited to 'drivers') diff --git a/arch/arm/mach-sa1100/include/mach/nanoengine.h b/arch/arm/mach-sa1100/include/mach/nanoengine.h new file mode 100644 index 000000000000..053776645526 --- /dev/null +++ b/arch/arm/mach-sa1100/include/mach/nanoengine.h @@ -0,0 +1,30 @@ +/* + * arch/arm/mach-sa1100/include/mach/nanoengine.h + * + * This file contains the hardware specific definitions for nanoEngine. + * Only include this file from SA1100-specific files. + * + * Copyright (C) 2010 Marcelo Roberto Jimenez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __ASM_ARCH_NANOENGINE_H +#define __ASM_ARCH_NANOENGINE_H + +#define GPIO_PC_READY0 GPIO_GPIO(11) /* ready for socket 0 (active high)*/ +#define GPIO_PC_READY1 GPIO_GPIO(12) /* ready for socket 1 (active high) */ +#define GPIO_PC_CD0 GPIO_GPIO(13) /* detect for socket 0 (active low) */ +#define GPIO_PC_CD1 GPIO_GPIO(14) /* detect for socket 1 (active low) */ +#define GPIO_PC_RESET0 GPIO_GPIO(15) /* reset socket 0 */ +#define GPIO_PC_RESET1 GPIO_GPIO(16) /* reset socket 1 */ + +#define NANOENGINE_IRQ_GPIO_PC_READY0 IRQ_GPIO11 +#define NANOENGINE_IRQ_GPIO_PC_READY1 IRQ_GPIO12 +#define NANOENGINE_IRQ_GPIO_PC_CD0 IRQ_GPIO13 +#define NANOENGINE_IRQ_GPIO_PC_CD1 IRQ_GPIO14 + +#endif + diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c index e4a03099e2a3..844ec61415a7 100644 --- a/arch/arm/mach-sa1100/nanoengine.c +++ b/arch/arm/mach-sa1100/nanoengine.c @@ -3,7 +3,7 @@ * * Bright Star Engineering's nanoEngine board init code. * - * Copyright (C) 2009 Marcelo Roberto Jimenez + * Copyright (C) 2010 Marcelo Roberto Jimenez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 8d9386a22eb3..a565300a19c8 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -50,8 +50,9 @@ sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1100_cs-y += sa1100_generic.o sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o -sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o +sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-$(CONFIG_SA1100_NANOENGINE) += sa1100_nanoengine.o sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 945857f8c284..ff8a027a4afb 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -53,6 +53,9 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600) pcmcia_h3600_init, #endif +#ifdef CONFIG_SA1100_NANOENGINE + pcmcia_nanoengine_init, +#endif #ifdef CONFIG_SA1100_SHANNON pcmcia_shannon_init, #endif diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h index 794f96a35bba..adb08dbc723f 100644 --- a/drivers/pcmcia/sa1100_generic.h +++ b/drivers/pcmcia/sa1100_generic.h @@ -13,6 +13,7 @@ extern int pcmcia_freebird_init(struct device *); extern int pcmcia_gcplus_init(struct device *); extern int pcmcia_graphicsmaster_init(struct device *); extern int pcmcia_h3600_init(struct device *); +extern int pcmcia_nanoengine_init(struct device *); extern int pcmcia_pangolin_init(struct device *); extern int pcmcia_pfs168_init(struct device *); extern int pcmcia_shannon_init(struct device *); diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c new file mode 100644 index 000000000000..3d2652e2f5ae --- /dev/null +++ b/drivers/pcmcia/sa1100_nanoengine.c @@ -0,0 +1,219 @@ +/* + * drivers/pcmcia/sa1100_nanoengine.c + * + * PCMCIA implementation routines for BSI nanoEngine. + * + * In order to have a fully functional pcmcia subsystem in a BSE nanoEngine + * board you should carefully read this: + * http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/ + * + * Copyright (C) 2010 Marcelo Roberto Jimenez + * + * Based on original work for kernel 2.4 by + * Miguel Freitas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "sa1100_generic.h" + +static struct pcmcia_irqs irqs_skt0[] = { + /* socket, IRQ, name */ + { 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" }, +}; + +static struct pcmcia_irqs irqs_skt1[] = { + /* socket, IRQ, name */ + { 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" }, +}; + +struct nanoengine_pins { + unsigned input_pins; + unsigned output_pins; + unsigned clear_outputs; + unsigned transition_pins; + unsigned pci_irq; + struct pcmcia_irqs *pcmcia_irqs; + unsigned pcmcia_irqs_size; +}; + +static struct nanoengine_pins nano_skts[] = { + { + .input_pins = GPIO_PC_READY0 | GPIO_PC_CD0, + .output_pins = GPIO_PC_RESET0, + .clear_outputs = GPIO_PC_RESET0, + .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD0, + .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY0, + .pcmcia_irqs = irqs_skt0, + .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt0) + }, { + .input_pins = GPIO_PC_READY1 | GPIO_PC_CD1, + .output_pins = GPIO_PC_RESET1, + .clear_outputs = GPIO_PC_RESET1, + .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD1, + .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY1, + .pcmcia_irqs = irqs_skt1, + .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt1) + } +}; + +unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts); + +static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return -ENXIO; + + GPDR &= ~nano_skts[i].input_pins; + GPDR |= nano_skts[i].output_pins; + GPCR = nano_skts[i].clear_outputs; + set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH); + skt->socket.pci_irq = nano_skts[i].pci_irq; + + return soc_pcmcia_request_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +/* + * Release all resources. + */ +static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + soc_pcmcia_free_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +static int nanoengine_pcmcia_configure_socket( + struct soc_pcmcia_socket *skt, const socket_state_t *state) +{ + unsigned reset; + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return -ENXIO; + + switch (i) { + case 0: + reset = GPIO_PC_RESET0; + break; + case 1: + reset = GPIO_PC_RESET1; + break; + default: + return -ENXIO; + } + + if (state->flags & SS_RESET) + GPSR = reset; + else + GPCR = reset; + + return 0; +} + +static void nanoengine_pcmcia_socket_state( + struct soc_pcmcia_socket *skt, struct pcmcia_state *state) +{ + unsigned long levels = GPLR; + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + memset(state, 0, sizeof(struct pcmcia_state)); + switch (i) { + case 0: + state->ready = (levels & GPIO_PC_READY0) ? 1 : 0; + state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0; + break; + case 1: + state->ready = (levels & GPIO_PC_READY1) ? 1 : 0; + state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0; + break; + default: + return; + } + state->bvd1 = 1; + state->bvd2 = 1; + state->wrprot = 0; /* Not available */ + state->vs_3v = 1; /* Can only apply 3.3V */ + state->vs_Xv = 0; +} + +/* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ +static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + soc_pcmcia_enable_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +/* + * Disable card status IRQs on suspend. + */ +static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + soc_pcmcia_disable_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +static struct pcmcia_low_level nanoengine_pcmcia_ops = { + .owner = THIS_MODULE, + + .hw_init = nanoengine_pcmcia_hw_init, + .hw_shutdown = nanoengine_pcmcia_hw_shutdown, + + .configure_socket = nanoengine_pcmcia_configure_socket, + .socket_state = nanoengine_pcmcia_socket_state, + .socket_init = nanoengine_pcmcia_socket_init, + .socket_suspend = nanoengine_pcmcia_socket_suspend, +}; + +int pcmcia_nanoengine_init(struct device *dev) +{ + int ret = -ENODEV; + + if (machine_is_nanoengine()) + ret = sa11xx_drv_pcmcia_probe( + dev, &nanoengine_pcmcia_ops, 0, 2); + + return ret; +} + -- cgit v1.2.3