ixgbe: add methods for combined read and write operations
authorDon Skidmore <donald.c.skidmore@intel.com>
Sat, 29 Nov 2014 05:22:43 +0000 (05:22 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 5 Dec 2014 17:13:07 +0000 (09:13 -0800)
Some X550 procedures will be using CS4227 PHY and need to
perform combined read and write operations.  This patch
adds those methods.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h

index a17495831d84c1e86f35f427b9b3976cbc56b205..8a2be444113dd65044d30f7831a81ba1d118f58f 100644 (file)
@@ -49,6 +49,188 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
 static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
 static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw);
 
+/**
+ *  ixgbe_out_i2c_byte_ack - Send I2C byte with ack
+ *  @hw: pointer to the hardware structure
+ *  @byte: byte to send
+ *
+ *  Returns an error code on error.
+ **/
+static s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte)
+{
+       s32 status;
+
+       status = ixgbe_clock_out_i2c_byte(hw, byte);
+       if (status)
+               return status;
+       return ixgbe_get_i2c_ack(hw);
+}
+
+/**
+ *  ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack
+ *  @hw: pointer to the hardware structure
+ *  @byte: pointer to a u8 to receive the byte
+ *
+ *  Returns an error code on error.
+ **/
+static s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte)
+{
+       s32 status;
+
+       status = ixgbe_clock_in_i2c_byte(hw, byte);
+       if (status)
+               return status;
+       /* ACK */
+       return ixgbe_clock_out_i2c_bit(hw, false);
+}
+
+/**
+ *  ixgbe_ones_comp_byte_add - Perform one's complement addition
+ *  @add1: addend 1
+ *  @add2: addend 2
+ *
+ *  Returns one's complement 8-bit sum.
+ **/
+static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
+{
+       u16 sum = add1 + add2;
+
+       sum = (sum & 0xFF) + (sum >> 8);
+       return sum & 0xFF;
+}
+
+/**
+ *  ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
+ *  @hw: pointer to the hardware structure
+ *  @addr: I2C bus address to read from
+ *  @reg: I2C device register to read from
+ *  @val: pointer to location to receive read value
+ *
+ *  Returns an error code on error.
+ **/
+s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
+                                   u16 reg, u16 *val)
+{
+       u32 swfw_mask = hw->phy.phy_semaphore_mask;
+       int max_retry = 10;
+       int retry = 0;
+       u8 csum_byte;
+       u8 high_bits;
+       u8 low_bits;
+       u8 reg_high;
+       u8 csum;
+
+       reg_high = ((reg >> 7) & 0xFE) | 1;     /* Indicate read combined */
+       csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
+       csum = ~csum;
+       do {
+               if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+                       return IXGBE_ERR_SWFW_SYNC;
+               ixgbe_i2c_start(hw);
+               /* Device Address and write indication */
+               if (ixgbe_out_i2c_byte_ack(hw, addr))
+                       goto fail;
+               /* Write bits 14:8 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg_high))
+                       goto fail;
+               /* Write bits 7:0 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
+                       goto fail;
+               /* Write csum */
+               if (ixgbe_out_i2c_byte_ack(hw, csum))
+                       goto fail;
+               /* Re-start condition */
+               ixgbe_i2c_start(hw);
+               /* Device Address and read indication */
+               if (ixgbe_out_i2c_byte_ack(hw, addr | 1))
+                       goto fail;
+               /* Get upper bits */
+               if (ixgbe_in_i2c_byte_ack(hw, &high_bits))
+                       goto fail;
+               /* Get low bits */
+               if (ixgbe_in_i2c_byte_ack(hw, &low_bits))
+                       goto fail;
+               /* Get csum */
+               if (ixgbe_clock_in_i2c_byte(hw, &csum_byte))
+                       goto fail;
+               /* NACK */
+               if (ixgbe_clock_out_i2c_bit(hw, false))
+                       goto fail;
+               ixgbe_i2c_stop(hw);
+               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               *val = (high_bits << 8) | low_bits;
+               return 0;
+
+fail:
+               ixgbe_i2c_bus_clear(hw);
+               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               retry++;
+               if (retry < max_retry)
+                       hw_dbg(hw, "I2C byte read combined error - Retry.\n");
+               else
+                       hw_dbg(hw, "I2C byte read combined error.\n");
+       } while (retry < max_retry);
+
+       return IXGBE_ERR_I2C;
+}
+
+/**
+ *  ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
+ *  @hw: pointer to the hardware structure
+ *  @addr: I2C bus address to write to
+ *  @reg: I2C device register to write to
+ *  @val: value to write
+ *
+ *  Returns an error code on error.
+ **/
+s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
+                                    u8 addr, u16 reg, u16 val)
+{
+       int max_retry = 1;
+       int retry = 0;
+       u8 reg_high;
+       u8 csum;
+
+       reg_high = (reg >> 7) & 0xFE;   /* Indicate write combined */
+       csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
+       csum = ixgbe_ones_comp_byte_add(csum, val >> 8);
+       csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
+       csum = ~csum;
+       do {
+               ixgbe_i2c_start(hw);
+               /* Device Address and write indication */
+               if (ixgbe_out_i2c_byte_ack(hw, addr))
+                       goto fail;
+               /* Write bits 14:8 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg_high))
+                       goto fail;
+               /* Write bits 7:0 */
+               if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF))
+                       goto fail;
+               /* Write data 15:8 */
+               if (ixgbe_out_i2c_byte_ack(hw, val >> 8))
+                       goto fail;
+               /* Write data 7:0 */
+               if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF))
+                       goto fail;
+               /* Write csum */
+               if (ixgbe_out_i2c_byte_ack(hw, csum))
+                       goto fail;
+               ixgbe_i2c_stop(hw);
+               return 0;
+
+fail:
+               ixgbe_i2c_bus_clear(hw);
+               retry++;
+               if (retry < max_retry)
+                       hw_dbg(hw, "I2C byte write combined error - Retry.\n");
+               else
+                       hw_dbg(hw, "I2C byte write combined error.\n");
+       } while (retry < max_retry);
+
+       return IXGBE_ERR_I2C;
+}
+
 /**
  *  ixgbe_identify_phy_generic - Get physical layer module
  *  @hw: pointer to hardware structure
index 54071ed17e3b3d589d8250f4536f622e796049dc..badd07281b780bee1c7aa829c799023822ce8b20 100644 (file)
@@ -157,4 +157,8 @@ s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                   u8 *sff8472_data);
 s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                   u8 eeprom_data);
+s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
+                                   u16 reg, u16 *val);
+s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
+                                    u16 reg, u16 val);
 #endif /* _IXGBE_PHY_H_ */
index 6cff91e1bd87208c222216460a2666b6dc69ed30..14b43b9f49db7e624361b8675d00863036280ca7 100644 (file)
@@ -2960,6 +2960,8 @@ struct ixgbe_phy_operations {
        s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *);
        s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
        s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
+       s32 (*read_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val);
+       s32 (*write_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val);
        s32 (*check_overtemp)(struct ixgbe_hw *);
 };