+/* Minimum timing constants */
+#define EECK_EDGE_TIME 3 /* 3us - max(adm 2.5us, 93c 1us) */
+#define EEDI_SETUP_TIME 1 /* 1us - max(adm 10ns, 93c 400ns) */
+#define EECS_SETUP_TIME 1 /* 1us - max(adm no, 93c 200ns) */
+
+static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits)
+{
+ int i, len = (bits + 7) / 8;
+ u8 mask;
+
+ gpio_set_value(priv->eecs, cs);
+ udelay(EECK_EDGE_TIME);
+
+ /* Byte assemble from MSB to LSB */
+ for (i = 0; i < len; i++) {
+ /* Bit bang from MSB to LSB */
+ for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) {
+ /* Clock low */
+ gpio_set_value(priv->eesk, 0);
+ udelay(EECK_EDGE_TIME);
+
+ /* Output on rising edge */
+ gpio_set_value(priv->eedi, (mask & buf[i]));
+ udelay(EEDI_SETUP_TIME);
+
+ /* Clock high */
+ gpio_set_value(priv->eesk, 1);
+ udelay(EECK_EDGE_TIME);
+ }
+ }
+
+ /* Clock low */
+ gpio_set_value(priv->eesk, 0);
+ udelay(EECK_EDGE_TIME);
+
+ if (cs)
+ gpio_set_value(priv->eecs, 0);
+}
+
+static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits)
+{
+ int i, len = (bits + 7) / 8;
+ u8 mask;
+
+ gpio_set_value(priv->eecs, cs);
+ udelay(EECK_EDGE_TIME);
+
+ /* Byte assemble from MSB to LSB */
+ for (i = 0; i < len; i++) {
+ u8 byte;
+
+ /* Bit bang from MSB to LSB */
+ for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) {
+ u8 gp;
+
+ /* Clock low */
+ gpio_set_value(priv->eesk, 0);
+ udelay(EECK_EDGE_TIME);
+
+ /* Input on rising edge */
+ gp = gpio_get_value(priv->eedi);
+ if (gp)
+ byte |= mask;
+
+ /* Clock high */
+ gpio_set_value(priv->eesk, 1);
+ udelay(EECK_EDGE_TIME);
+ }
+
+ *buf++ = byte;
+ }
+
+ /* Clock low */
+ gpio_set_value(priv->eesk, 0);
+ udelay(EECK_EDGE_TIME);
+
+ if (cs)
+ gpio_set_value(priv->eecs, 0);
+}
+
+/* Advance clock(s) */
+static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks)
+{
+ int i;
+ for (i = 0; i < clocks; i++) {
+ /* Clock high */
+ gpio_set_value(priv->eesk, 1);
+ udelay(EECK_EDGE_TIME);
+
+ /* Clock low */
+ gpio_set_value(priv->eesk, 0);
+ udelay(EECK_EDGE_TIME);
+ }
+}
+
+static u16
+adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg)
+{
+ /* cmd: 01 10 T DD R RRRRRR */
+ u8 bits[6] = {
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ (0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6),
+ ((reg&63)<<2)
+ };
+
+ u8 rbits[4];
+
+ /* Enable GPIO outputs with all pins to 0 */
+ gpio_direction_output(priv->eecs, 0);
+ gpio_direction_output(priv->eesk, 0);
+ gpio_direction_output(priv->eedi, 0);
+
+ adm6996_gpio_write(priv, 0, bits, 46);
+ gpio_direction_input(priv->eedi);
+ adm6996_gpio_adclk(priv, 2);
+ adm6996_gpio_read(priv, 0, rbits, 32);
+
+ /* Extra clock(s) required per datasheet */
+ adm6996_gpio_adclk(priv, 2);
+
+ /* Disable GPIO outputs */
+ gpio_direction_input(priv->eecs);
+ gpio_direction_input(priv->eesk);
+
+ /* EEPROM has 16-bit registers, but pumps out two registers in one request */
+ return (reg & 0x01 ? (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3]));
+}
+
+/* Write chip configuration register */
+/* Follow 93c66 timing and chip's min EEPROM timing requirement */
+static void
+adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+ /* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */
+ u8 bits[4] = {
+ (0x05 << 5) | (reg >> 3),
+ (reg << 5) | (u8)(val >> 11),
+ (u8)(val >> 3),
+ (u8)(val << 5)
+ };
+
+ /* Enable GPIO outputs with all pins to 0 */
+ gpio_direction_output(priv->eecs, 0);
+ gpio_direction_output(priv->eesk, 0);
+ gpio_direction_output(priv->eedi, 0);
+
+ /* Write cmd. Total 27 bits */
+ adm6996_gpio_write(priv, 1, bits, 27);
+
+ /* Extra clock(s) required per datasheet */
+ adm6996_gpio_adclk(priv, 2);
+
+ /* Disable GPIO outputs */
+ gpio_direction_input(priv->eecs);
+ gpio_direction_input(priv->eesk);
+ gpio_direction_input(priv->eedi);
+}