aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/serial_cs.c
diff options
context:
space:
mode:
authorPetr Vandrovec <vandrove@vc.cvut.cz>2006-02-10 05:04:00 -0500
committerDominik Brodowski <linux@dominikbrodowski.net>2006-03-31 10:27:07 -0500
commit30bac7aa0e3678c79ff00fc9372f34712eeb34fc (patch)
treef15b6915b804b3d06e783e657c60bc96948ec283 /drivers/serial/serial_cs.c
parentd6ff5a8532b553e4d85ea65c99eaa0794edf5311 (diff)
[PATCH] pcmcia: Add support for Possio GCC AKA PCMCIA Siemens MC45
This ugly hack add support for Siemens MC45 PCMCIA GPRS card (which is identical to Possio GCC, and which is offered by one of our local GPRS providers). Card has unfortunate feature that after poweron oxcf950 chip is fully powered and works, but attached MC45 modem is powered down :-( There is a special sequence (which takes 1 sec :-( ) to poweron MC45 (and after MC45 powers on, it takes more than 2 secs until firmware fully boots...) which needs to be executed after all powerons. I'm really not familiar with PCMCIA subsystem, so I have no idea whether I should issue request_region() on rest of oxcf950 address range (0-7 is UART, 8-F are special configuration registers), or how this should be better integrated with PM system and so on - I just put it in same place where another hack already lived... Card uses 18.432MHz XTAL, so to get it to work you must add lines below to the /etc/pcmcia/serial.opts. case "$MANFID-$FUNCID-$PRODID_1-$PRODID_2-$PRODID_3-$PRODID_4" in '030c,0003-2-GPRS-CARD--') SERIAL_OPTS="baud_base 1152000" ;; esac Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/serial/serial_cs.c')
-rw-r--r--drivers/serial/serial_cs.c52
1 files changed, 46 insertions, 6 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 389d847cd1b4..2c70773543e0 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -41,6 +41,7 @@
41#include <linux/string.h> 41#include <linux/string.h>
42#include <linux/timer.h> 42#include <linux/timer.h>
43#include <linux/serial_core.h> 43#include <linux/serial_core.h>
44#include <linux/delay.h>
44#include <linux/major.h> 45#include <linux/major.h>
45#include <asm/io.h> 46#include <asm/io.h>
46#include <asm/system.h> 47#include <asm/system.h>
@@ -102,6 +103,8 @@ struct serial_info {
102 int multi; 103 int multi;
103 int slave; 104 int slave;
104 int manfid; 105 int manfid;
106 int prodid;
107 int c950ctrl;
105 dev_node_t node[4]; 108 dev_node_t node[4];
106 int line[4]; 109 int line[4];
107}; 110};
@@ -116,6 +119,33 @@ struct serial_cfg_mem {
116static int serial_config(struct pcmcia_device * link); 119static int serial_config(struct pcmcia_device * link);
117 120
118 121
122static void wakeup_card(struct serial_info *info)
123{
124 int ctrl = info->c950ctrl;
125
126 if (info->manfid == MANFID_OXSEMI) {
127 outb(12, ctrl + 1);
128 } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
129 /* request_region? oxsemi branch does no request_region too... */
130 /* This sequence is needed to properly initialize MC45 attached to OXCF950.
131 * I tried decreasing these msleep()s, but it worked properly (survived
132 * 1000 stop/start operations) with these timeouts (or bigger). */
133 outb(0xA, ctrl + 1);
134 msleep(100);
135 outb(0xE, ctrl + 1);
136 msleep(300);
137 outb(0xC, ctrl + 1);
138 msleep(100);
139 outb(0xE, ctrl + 1);
140 msleep(200);
141 outb(0xF, ctrl + 1);
142 msleep(100);
143 outb(0xE, ctrl + 1);
144 msleep(100);
145 outb(0xC, ctrl + 1);
146 }
147}
148
119/*====================================================================== 149/*======================================================================
120 150
121 After a card is removed, serial_remove() will unregister 151 After a card is removed, serial_remove() will unregister
@@ -161,6 +191,7 @@ static int serial_resume(struct pcmcia_device *link)
161 191
162 for (i = 0; i < info->ndev; i++) 192 for (i = 0; i < info->ndev; i++)
163 serial8250_resume_port(info->line[i]); 193 serial8250_resume_port(info->line[i]);
194 wakeup_card(info);
164 } 195 }
165 196
166 return 0; 197 return 0;
@@ -503,15 +534,23 @@ static int multi_config(struct pcmcia_device * link)
503 } 534 }
504 535
505 /* The Oxford Semiconductor OXCF950 cards are in fact single-port: 536 /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
506 8 registers are for the UART, the others are extra registers */ 537 * 8 registers are for the UART, the others are extra registers.
507 if (info->manfid == MANFID_OXSEMI) { 538 * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
539 */
540 if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
541 info->prodid == PRODID_POSSIO_GCC)) {
542 int err;
543
508 if (cf->index == 1 || cf->index == 3) { 544 if (cf->index == 1 || cf->index == 3) {
509 setup_serial(link, info, base2, link->irq.AssignedIRQ); 545 err = setup_serial(link, info, base2,
510 outb(12, link->io.BasePort1 + 1); 546 link->irq.AssignedIRQ);
547 base2 = link->io.BasePort1;
511 } else { 548 } else {
512 setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); 549 err = setup_serial(link, info, link->io.BasePort1,
513 outb(12, base2 + 1); 550 link->irq.AssignedIRQ);
514 } 551 }
552 info->c950ctrl = base2;
553 wakeup_card(info);
515 rc = 0; 554 rc = 0;
516 goto free_cfg_mem; 555 goto free_cfg_mem;
517 } 556 }
@@ -583,6 +622,7 @@ static int serial_config(struct pcmcia_device * link)
583 tuple->DesiredTuple = CISTPL_MANFID; 622 tuple->DesiredTuple = CISTPL_MANFID;
584 if (first_tuple(link, tuple, parse) == CS_SUCCESS) { 623 if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
585 info->manfid = parse->manfid.manf; 624 info->manfid = parse->manfid.manf;
625 info->prodid = le16_to_cpu(buf[1]);
586 for (i = 0; i < MULTI_COUNT; i++) 626 for (i = 0; i < MULTI_COUNT; i++)
587 if ((info->manfid == multi_id[i].manfid) && 627 if ((info->manfid == multi_id[i].manfid) &&
588 (parse->manfid.card == multi_id[i].prodid)) 628 (parse->manfid.card == multi_id[i].prodid))