[PATCH] yenta: make ToPIC95 bridges work with 16bit cards
authorDaniel Ritz <daniel.ritz@gmx.ch>
Tue, 6 Sep 2005 22:16:50 +0000 (15:16 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 7 Sep 2005 23:57:21 +0000 (16:57 -0700)
ToPIC95 brides (and maybe some other too) require to use the ExCA registers
to power up the socket if a 16bit card is pluged.  allow socket drivers to
set a flag so that yenta does just that.  also clean up yenta_get_status()
a bit to use the new yenta_get_power() function.

Side note: ToPIC97 bridges (at least in Rev.5 i have) don't require this.

Ryan Underwood <nemesis-lists@icequake.net> said:

 According to the mail that David Hinds received from a Toshiba engineer,
 ToPIC95 and 97 do require this, and ToPIC100 does not.  Maybe you have a
 later revision.

 For all chips, 16-bit cards can be enabled through ExCA.  So doesn't it
 make sense just to make this the default behavior for all Toshiba chips,
 to avoid corner cases showing up later?

Daniel responded:

 I disagree with ryan to change anything for topic97 bridges.  they work.
 and I couldn't find (read google) any report of a topic97 breaking on
 applying power with the CB registers.

 I'm having several toshba notebooks at work (and home) with topic95,97,100
 bridges.  Only the ones with a topic95 didn't work.

Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/pcmcia/topic.h
drivers/pcmcia/yenta_socket.c
drivers/pcmcia/yenta_socket.h

index be420bb..edccfa5 100644 (file)
 #define  TOPIC97_AVS_AUDIO_CONTROL     0x02
 #define  TOPIC97_AVS_VIDEO_CONTROL     0x01
 
+#define TOPIC_EXCA_IF_CONTROL          0x3e    /* 8 bit */
+#define TOPIC_EXCA_IFC_33V_ENA         0x01
 
 static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff)
 {
@@ -137,4 +139,19 @@ static int topic97_override(struct yenta_socket *socket)
        return 0;
 }
 
+
+static int topic95_override(struct yenta_socket *socket)
+{
+       u8 fctrl;
+
+       /* enable 3.3V support for 16bit cards */
+       fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL);
+       exca_writeb(socket, TOPIC_EXCA_IF_CONTROL, fctrl | TOPIC_EXCA_IFC_33V_ENA);
+
+       /* tell yenta to use exca registers to power 16bit cards */
+       socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF;
+
+       return 0;
+}
+
 #endif /* _LINUX_TOPIC_H */
index 62fd705..0347a29 100644 (file)
@@ -184,22 +184,52 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value)
        return 0;
 }
 
-static int yenta_Vcc_power(u32 control)
+static void yenta_get_power(struct yenta_socket *socket, socket_state_t *state)
 {
-       switch (control & CB_SC_VCC_MASK) {
-       case CB_SC_VCC_5V: return 50;
-       case CB_SC_VCC_3V: return 33;
-       default: return 0;
-       }
-}
+       if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+           (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+               u8 reg, vcc, vpp;
+
+               reg = exca_readb(socket, I365_POWER);
+               vcc = reg & I365_VCC_MASK;
+               vpp = reg & I365_VPP1_MASK;
+               state->Vcc = state->Vpp = 0;
+
+               if (socket->flags & YENTA_16BIT_POWER_DF) {
+                       if (vcc == I365_VCC_3V)
+                               state->Vcc = 33;
+                       if (vcc == I365_VCC_5V)
+                               state->Vcc = 50;
+                       if (vpp == I365_VPP1_5V)
+                               state->Vpp = state->Vcc;
+                       if (vpp == I365_VPP1_12V)
+                               state->Vpp = 120;
+               } else {
+                       if (reg & I365_VCC_5V) {
+                               state->Vcc = 50;
+                               if (vpp == I365_VPP1_5V)
+                                       state->Vpp = 50;
+                               if (vpp == I365_VPP1_12V)
+                                       state->Vpp = 120;
+                       }
+               }
+       } else {
+               u32 control;
 
-static int yenta_Vpp_power(u32 control)
-{
-       switch (control & CB_SC_VPP_MASK) {
-       case CB_SC_VPP_12V: return 120;
-       case CB_SC_VPP_5V: return 50;
-       case CB_SC_VPP_3V: return 33;
-       default: return 0;
+               control = cb_readl(socket, CB_SOCKET_CONTROL);
+
+               switch (control & CB_SC_VCC_MASK) {
+               case CB_SC_VCC_5V: state->Vcc = 50; break;
+               case CB_SC_VCC_3V: state->Vcc = 33; break;
+               default: state->Vcc = 0;
+               }
+
+               switch (control & CB_SC_VPP_MASK) {
+               case CB_SC_VPP_12V: state->Vpp = 120; break;
+               case CB_SC_VPP_5V: state->Vpp = 50; break;
+               case CB_SC_VPP_3V: state->Vpp = 33; break;
+               default: state->Vpp = 0;
+               }
        }
 }
 
@@ -211,8 +241,7 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
 
        control = cb_readl(socket, CB_SOCKET_CONTROL);
 
-       state->Vcc = yenta_Vcc_power(control);
-       state->Vpp = yenta_Vpp_power(control);
+       yenta_get_power(socket, state);
        state->io_irq = socket->io_irq;
 
        if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
@@ -246,19 +275,54 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
 
 static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state)
 {
-       u32 reg = 0;    /* CB_SC_STPCLK? */
-       switch (state->Vcc) {
-       case 33: reg = CB_SC_VCC_3V; break;
-       case 50: reg = CB_SC_VCC_5V; break;
-       default: reg = 0; break;
-       }
-       switch (state->Vpp) {
-       case 33:  reg |= CB_SC_VPP_3V; break;
-       case 50:  reg |= CB_SC_VPP_5V; break;
-       case 120: reg |= CB_SC_VPP_12V; break;
+       /* some birdges require to use the ExCA registers to power 16bit cards */
+       if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) &&
+           (socket->flags & YENTA_16BIT_POWER_EXCA)) {
+               u8 reg, old;
+               reg = old = exca_readb(socket, I365_POWER);
+               reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK);
+
+               /* i82365SL-DF style */
+               if (socket->flags & YENTA_16BIT_POWER_DF) {
+                       switch (state->Vcc) {
+                       case 33: reg |= I365_VCC_3V; break;
+                       case 50: reg |= I365_VCC_5V; break;
+                       default: reg = 0; break;
+                       }
+                       switch (state->Vpp) {
+                       case 33:
+                       case 50: reg |= I365_VPP1_5V; break;
+                       case 120: reg |= I365_VPP1_12V; break;
+                       }
+               } else {
+                       /* i82365SL-B style */
+                       switch (state->Vcc) {
+                       case 50: reg |= I365_VCC_5V; break;
+                       default: reg = 0; break;
+                       }
+                       switch (state->Vpp) {
+                       case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+                       case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+                       }
+               }
+
+               if (reg != old)
+                       exca_writeb(socket, I365_POWER, reg);
+       } else {
+               u32 reg = 0;    /* CB_SC_STPCLK? */
+               switch (state->Vcc) {
+               case 33: reg = CB_SC_VCC_3V; break;
+               case 50: reg = CB_SC_VCC_5V; break;
+               default: reg = 0; break;
+               }
+               switch (state->Vpp) {
+               case 33:  reg |= CB_SC_VPP_3V; break;
+               case 50:  reg |= CB_SC_VPP_5V; break;
+               case 120: reg |= CB_SC_VPP_12V; break;
+               }
+               if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
+                       cb_writel(socket, CB_SOCKET_CONTROL, reg);
        }
-       if (reg != cb_readl(socket, CB_SOCKET_CONTROL))
-               cb_writel(socket, CB_SOCKET_CONTROL, reg);
 }
 
 static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
@@ -751,6 +815,7 @@ enum {
        CARDBUS_TYPE_TI12XX,
        CARDBUS_TYPE_TI1250,
        CARDBUS_TYPE_RICOH,
+       CARDBUS_TYPE_TOPIC95,
        CARDBUS_TYPE_TOPIC97,
        CARDBUS_TYPE_O2MICRO,
 };
@@ -789,6 +854,9 @@ static struct cardbus_type cardbus_type[] = {
                .save_state     = ricoh_save_state,
                .restore_state  = ricoh_restore_state,
        },
+       [CARDBUS_TYPE_TOPIC95]  = {
+               .override       = topic95_override,
+       },
        [CARDBUS_TYPE_TOPIC97]  = {
                .override       = topic97_override,
        },
@@ -1196,6 +1264,7 @@ static struct pci_device_id yenta_table [] = {
        CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH),
        CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH),
 
+       CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95),
        CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
        CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
 
index 4e637ee..4e75e9e 100644 (file)
  */
 #define CB_MEM_PAGE(map)       (0x40 + (map))
 
+
+/* control how 16bit cards are powered */
+#define YENTA_16BIT_POWER_EXCA 0x00000001
+#define YENTA_16BIT_POWER_DF   0x00000002
+
+
 struct yenta_socket;
 
 struct cardbus_type {
@@ -113,6 +119,8 @@ struct yenta_socket {
        struct pcmcia_socket socket;
        struct cardbus_type *type;
 
+       u32 flags;
+
        /* for PCI interrupt probing */
        unsigned int probe_status;