bnx2x: GPIO accessories
authorEilon Greenstein <eilong@broadcom.com>
Thu, 12 Feb 2009 08:36:52 +0000 (08:36 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 16 Feb 2009 07:31:20 +0000 (23:31 -0800)
A GPIO is used with the 8726 PHY. Adding the GPIO related functions in this

Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bnx2x.h
drivers/net/bnx2x_main.c
drivers/net/bnx2x_reg.h

index 2397a89..d66be72 100644 (file)
@@ -982,7 +982,9 @@ struct bnx2x {
 void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
 void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
                      u32 len32);
+int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
+int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 
 static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                           int wait)
index 9c40b02..95f8e58 100644 (file)
@@ -626,8 +626,8 @@ static void bnx2x_int_enable(struct bnx2x *bp)
                if (IS_E1HMF(bp)) {
                        val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
                        if (bp->port.pmf)
-                               /* enable nig attention */
-                               val |= 0x0100;
+                               /* enable nig and gpio3 attention */
+                               val |= 0x1100;
                } else
                        val = 0xffff;
 
@@ -1836,6 +1836,36 @@ static void bnx2x_release_phy_lock(struct bnx2x *bp)
        mutex_unlock(&bp->port.phy_mutex);
 }
 
+int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
+{
+       /* The GPIO should be swapped if swap register is set and active */
+       int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+                        REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
+       int gpio_shift = gpio_num +
+                       (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+       u32 gpio_mask = (1 << gpio_shift);
+       u32 gpio_reg;
+       int value;
+
+       if (gpio_num > MISC_REGISTERS_GPIO_3) {
+               BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+               return -EINVAL;
+       }
+
+       /* read GPIO value */
+       gpio_reg = REG_RD(bp, MISC_REG_GPIO);
+
+       /* get the requested pin value */
+       if ((gpio_reg & gpio_mask) == gpio_mask)
+               value = 1;
+       else
+               value = 0;
+
+       DP(NETIF_MSG_LINK, "pin %d  value 0x%x\n", gpio_num, value);
+
+       return value;
+}
+
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
 {
        /* The GPIO should be swapped if swap register is set and active */
@@ -1889,6 +1919,52 @@ int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
        return 0;
 }
 
+int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
+{
+       /* The GPIO should be swapped if swap register is set and active */
+       int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+                        REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
+       int gpio_shift = gpio_num +
+                       (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+       u32 gpio_mask = (1 << gpio_shift);
+       u32 gpio_reg;
+
+       if (gpio_num > MISC_REGISTERS_GPIO_3) {
+               BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+               return -EINVAL;
+       }
+
+       bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+       /* read GPIO int */
+       gpio_reg = REG_RD(bp, MISC_REG_GPIO_INT);
+
+       switch (mode) {
+       case MISC_REGISTERS_GPIO_INT_OUTPUT_CLR:
+               DP(NETIF_MSG_LINK, "Clear GPIO INT %d (shift %d) -> "
+                                  "output low\n", gpio_num, gpio_shift);
+               /* clear SET and set CLR */
+               gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
+               gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
+               break;
+
+       case MISC_REGISTERS_GPIO_INT_OUTPUT_SET:
+               DP(NETIF_MSG_LINK, "Set GPIO INT %d (shift %d) -> "
+                                  "output high\n", gpio_num, gpio_shift);
+               /* clear CLR and set SET */
+               gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
+               gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
+               break;
+
+       default:
+               break;
+       }
+
+       REG_WR(bp, MISC_REG_GPIO_INT, gpio_reg);
+       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+
+       return 0;
+}
+
 static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
 {
        u32 spio_mask = (1 << spio_num);
index 713b5f9..6fc1d0d 100644 (file)
    This is the result value of the pin; not the drive value. Writing these
    bits will have not effect. */
 #define MISC_REG_GPIO                                           0xa490
+/* [RW 8] These bits enable the GPIO_INTs to signals event to the
+   IGU/MCP.according to the following map: [0] p0_gpio_0; [1] p0_gpio_1; [2]
+   p0_gpio_2; [3] p0_gpio_3; [4] p1_gpio_0; [5] p1_gpio_1; [6] p1_gpio_2;
+   [7] p1_gpio_3; */
+#define MISC_REG_GPIO_EVENT_EN                                  0xa2bc
+/* [RW 32] GPIO INT. [31-28] OLD_CLR port1; [27-24] OLD_CLR port0; Writing a
+   '1' to these bit clears the corresponding bit in the #OLD_VALUE register.
+   This will acknowledge an interrupt on the falling edge of corresponding
+   GPIO input (reset value 0). [23-16] OLD_SET [23-16] port1; OLD_SET port0;
+   Writing a '1' to these bit sets the corresponding bit in the #OLD_VALUE
+   register. This will acknowledge an interrupt on the rising edge of
+   corresponding SPIO input (reset value 0). [15-12] OLD_VALUE [11-8] port1;
+   OLD_VALUE port0; RO; These bits indicate the old value of the GPIO input
+   value. When the ~INT_STATE bit is set; this bit indicates the OLD value
+   of the pin such that if ~INT_STATE is set and this bit is '0'; then the
+   interrupt is due to a low to high edge. If ~INT_STATE is set and this bit
+   is '1'; then the interrupt is due to a high to low edge (reset value 0).
+   [7-4] INT_STATE port1; [3-0] INT_STATE RO port0; These bits indicate the
+   current GPIO interrupt state for each GPIO pin. This bit is cleared when
+   the appropriate #OLD_SET or #OLD_CLR command bit is written. This bit is
+   set when the GPIO input does not match the current value in #OLD_VALUE
+   (reset value 0). */
+#define MISC_REG_GPIO_INT                                       0xa494
 /* [R 28] this field hold the last information that caused reserved
    attention. bits [19:0] - address; [22:20] function; [23] reserved;
    [27:24] the master that caused the attention - according to the following
 #define MISC_REGISTERS_GPIO_FLOAT_POS                           24
 #define MISC_REGISTERS_GPIO_HIGH                                1
 #define MISC_REGISTERS_GPIO_INPUT_HI_Z                          2
+#define MISC_REGISTERS_GPIO_INT_CLR_POS                         24
+#define MISC_REGISTERS_GPIO_INT_OUTPUT_CLR                      0
+#define MISC_REGISTERS_GPIO_INT_OUTPUT_SET                      1
+#define MISC_REGISTERS_GPIO_INT_SET_POS                         16
 #define MISC_REGISTERS_GPIO_LOW                                 0
 #define MISC_REGISTERS_GPIO_OUTPUT_HIGH                         1
 #define MISC_REGISTERS_GPIO_OUTPUT_LOW                          0
 #define AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT               (1<<11)
 #define AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT          (1<<13)
 #define AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR          (1<<12)
+#define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0                (1<<5)
+#define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1                (1<<9)
 #define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR                (1<<12)
 #define AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT               (1<<15)
 #define AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR               (1<<14)