/* Write Function of PROCFS attribute "/proc/b3450_reg" */ static ssize_t b3450_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { int value, ret_val; int offset = (int)file->f_pos; /* Only 4-Byte writes are supported */ if (count != REGISTER_LENGTH) { BCM_LOG_NOTICE(BCM_LOG_ID_I2C, "Only 4 Byte writes are supported \n"); return -EINVAL; } BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "The offset is %d; the count is %ld \n", offset, count); #ifdef __LITTLE_ENDIAN value = *((int *)buffer); #else value = swab32(*((int *)buffer)); #endif ret_val = bcm3450_write_reg(offset, value); /* If ret_val is less than 0, return ret_val; else return number of bytes read which is 4 */ return ((ret_val < 0) ? ret_val : REGISTER_LENGTH); }
u16 bcm3450_read_word(u8 offset) { struct i2c_msg msg[2]; u8 off, buf[4]; struct i2c_client *client = &pclient_data->client; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if(check_offset(offset, WORD_ALIGN)) return -1; /* BCM3450 requires the offset to be the register number */ off = offset/4; msg[0].addr = msg[1].addr = client->addr; msg[0].flags = msg[1].flags = client->flags & I2C_M_TEN; msg[0].len = 1; msg[0].buf = (char *)&off; msg[1].flags |= I2C_M_RD; msg[1].len = 4; msg[1].buf = buf; if(i2c_transfer(client->adapter, msg, 2) == 2) { return swab16(*((u16 *)&buf[offset % 4])); } return -1; }
u8 bcm3450_read_byte(u8 offset) { struct i2c_msg msg[2]; u8 off, buf[4]; struct i2c_client *client = &pclient_data->client; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if (offset > MAX_REG_OFFSET) { BCM_LOG_ERROR(BCM_LOG_ID_I2C, "Invalid offset. It should be less than " "%X \n", MAX_REG_OFFSET); return -1; } /* BCM3450 requires the offset to be the register number */ off = offset/4; msg[0].addr = msg[1].addr = client->addr; msg[0].flags = msg[1].flags = client->flags & I2C_M_TEN; msg[0].len = 1; msg[0].buf = (char *)&off; msg[1].flags |= I2C_M_RD; msg[1].len = 4; msg[1].buf = buf; if(i2c_transfer(client->adapter, msg, 2) == 2) { return buf[offset % 4]; } return -1; }
int bcm3450_write_word(u8 offset, u16 val) { u8 off; int tmp_val; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if(check_offset(offset, WORD_ALIGN)) return -1; /* Make the offset WORD aligned */ off = offset & 0xFC; /* Read */ tmp_val = bcm3450_read_reg(off); if (tmp_val < 0) { return -1; } /* Modify */ tmp_val = (tmp_val & (~(0xFFFF << ((offset % 4) * 8)))) | (val << ((offset % 4) * 8)); /* Write */ return bcm3450_write_reg(off, tmp_val); }
int bcm3450_read_reg(u8 offset) { struct i2c_msg msg[2]; int val; struct i2c_client *client = &pclient_data->client; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if(check_offset(offset, DWORD_ALIGN)) { return -EINVAL; } /* BCM3450 requires the offset to be the register number */ offset = offset/4; msg[0].addr = msg[1].addr = client->addr; msg[0].flags = msg[1].flags = client->flags & I2C_M_TEN; msg[0].len = 1; msg[0].buf = (char *)&offset; msg[1].flags |= I2C_M_RD; msg[1].len = 4; msg[1].buf = (char *)&val; /* On I2C bus, we receive LS byte first. So swap bytes as necessary */ if(i2c_transfer(client->adapter, msg, 2) == 2) return swab32(val); return -1; }
static int bcm3450_detach_client(struct i2c_client *client) { int err; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); #ifdef SYSFS_HOOKS sysfs_remove_group(&client->dev.kobj, &bcm3450_attr_group); #endif #ifdef PROCFS_HOOKS remove_proc_entry(PROC_ENTRY_NAME1, NULL); #ifdef MOCA_I2C_TEST remove_proc_entry(PROC_ENTRY_NAME2, NULL); #endif #endif err = i2c_detach_client(client); if (err) return err; kfree(i2c_get_clientdata(client)); return 0; }
/* Read the value from given bcm63000 register */ static inline int reg_read(uint32* offset) { int ret; ret = *offset; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "reg_read: offset = %lx, val is %x\n", (long int)offset, ret); return ret; }
static u32 bcm63000_func(struct i2c_adapter *adap) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); /*The SMBus commands are emulated on the I2C bus using i2c_xfer function*/ /*TBD:For correct SMBus Emulation, need to use the NOSTOP b/w given messges to the i2c_xfer */ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; /* TBD: The HW supports 10 bit addressing and some protocol magling */ /* I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MAGLING; */ }
/* *------------------------------------------------------------------------------ * Remove the L4 dest port from the Ingress QoS priority table *------------------------------------------------------------------------------ */ uint8_t iqos_rem_L4port( iqos_ipproto_t ipProto, uint16_t destPort, iqos_ent_t ent ) { unsigned long flags; uint8_t remIx = IQOS_INVALID_NEXT_IX; BCM_LOG_DEBUG( BCM_LOG_ID_IQ, "RemPort ent<%d> ipProto<%d> dport<%d> ", ent, ipProto, destPort); if ( unlikely(iqos_rem_L4port_hook_g == (iqos_rem_L4port_hook_t)NULL) ) goto iqos_rem_L4port_exit; IQOS_LOCK_IRQSAVE(); remIx = iqos_rem_L4port_hook_g( ipProto, destPort, ent ); IQOS_UNLOCK_IRQRESTORE(); iqos_rem_L4port_exit: BCM_LOG_DEBUG( BCM_LOG_ID_IQ, "remIx<%d> ", remIx); return remIx; }
/* *------------------------------------------------------------------------------ * Add the Ingress QoS priority, and type of entry for L4 Dest port. *------------------------------------------------------------------------------ */ uint8_t iqos_add_L4port( iqos_ipproto_t ipProto, uint16_t destPort, iqos_ent_t ent, iqos_prio_t prio ) { unsigned long flags; uint8_t addIx = IQOS_INVALID_NEXT_IX; BCM_LOG_DEBUG( BCM_LOG_ID_IQ, "AddPort ent<%d> ipProto<%d> dport<%d> prio<%d> ", ent, ipProto, destPort, prio ); if ( unlikely(iqos_add_L4port_hook_g == (iqos_add_L4port_hook_t)NULL) ) goto iqos_add_L4port_exit; IQOS_LOCK_IRQSAVE(); addIx = iqos_add_L4port_hook_g( ipProto, destPort, ent, prio ); IQOS_UNLOCK_IRQRESTORE(); iqos_add_L4port_exit: BCM_LOG_DEBUG( BCM_LOG_ID_IQ, "addIx<%d>", addIx ); return addIx; }
/* Transfers the given number of messages */ static int bcm63000_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *p, *q; int i, err = 0; /* Determine the FIFO length for Read and Write Transactions */ int fifo_len = (reg_read((uint32 *)&I2C->CtlHiReg) & I2C_CTLHI_REG_DATA_REG_SIZE) ? 32 : 8; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); /* The 63000 supports read_then_write and write_then_read formats, take advantage of these formats whenever possible */ if (num == 2) { p = &msgs[0]; q = &msgs[1]; /* We may be able to use the read_then_write and write_then_read formats only when the length of each message is less than fifo_len */ if (p->len <= fifo_len && q->len <= fifo_len) { if ((p->flags == I2C_M_RD) && (!(q->flags & I2C_M_RD))) { err = i2c_read_then_write(msgs, fifo_len); return (err < 0) ? err : 2; } else if ((!(p->flags & I2C_M_RD)) && (q->flags == I2C_M_RD)) { err = i2c_write_then_read(msgs, fifo_len); return (err < 0) ? err : 2; } } } /*TBD:See if we can use NO_STOP b/w multiple read and write transactions */ for (i = 0; !err && i < num; i++) { p = &msgs[i]; if (p->flags & I2C_M_RD) err = i2c_read(p, fifo_len); else err = i2c_write(p, fifo_len); } return (err < 0) ? err : i; }
ssize_t bcm3450_write(char *buf, size_t count) { struct i2c_client *client = &pclient_data->client; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if(check_offset(buf[0], DWORD_ALIGN)) return -1; if(count > MAX_TRANSACTION_SIZE) { BCM_LOG_NOTICE(BCM_LOG_ID_I2C, "count > %d is not yet supported \n", MAX_TRANSACTION_SIZE); return -1; } /* BCM3450 requires the offset to be the register number */ buf[0] = buf[0]/4; return i2c_master_send(client, buf, count); }
ssize_t bcm3450_read(char *buf, size_t count) { struct i2c_msg msg[2]; struct i2c_client *client = &pclient_data->client; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if(check_offset(buf[0], DWORD_ALIGN)) return -1; /* BCM3450 requires the offset to be the register number */ buf[0] = buf[0]/4; if(count > MAX_TRANSACTION_SIZE) { BCM_LOG_NOTICE(BCM_LOG_ID_I2C, "count > %d is not yet supported \n", MAX_TRANSACTION_SIZE); return -1; } /* First write the offset */ msg[0].addr = msg[1].addr = client->addr; msg[0].flags = msg[1].flags = client->flags & I2C_M_TEN; msg[0].len = 1; msg[0].buf = buf; /* Now read the data */ msg[1].flags |= I2C_M_RD; msg[1].len = count; msg[1].buf = buf; /* On I2C bus, we receive LS byte first. So swap bytes as necessary */ if(i2c_transfer(client->adapter, msg, 2) == 2) { return count; } return -1; }
/* Read Function of PROCFS attribute "/proc/b3450_reg" */ static ssize_t b3450_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int ret_val; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "The offset is %d; the count is %d \n", (int)off, count); /* Only 4-Byte reads are supported */ if (count != REGISTER_LENGTH) { BCM_LOG_NOTICE(BCM_LOG_ID_I2C, "Only 4 Byte reads are supported \n"); return -EINVAL; } /* See comments in the proc_file_read for info on 3 different * ways of returning data. We are following below method. * Set *start = an address within the buffer. * Put the data of the requested offset at *start. * Return the number of bytes of data placed there. * If this number is greater than zero and you * didn't signal eof and the reader is prepared to * take more data you will be called again with the * requested offset advanced by the number of bytes * absorbed. */ ret_val = bcm3450_read_reg((u8)off); #ifdef __LITTLE_ENDIAN *((int *)page) = ret_val; #else *((int *)page) = swab32(ret_val); #endif *start = page; *eof = 1; /* If ret_val is less than 0, return ret_val; else return number of bytes read which is 4 */ return ((ret_val < 0) ? ret_val : REGISTER_LENGTH); }
int bcm3450_write_reg(u8 offset, int val) { char buf[5]; struct i2c_client *client = &pclient_data->client; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if(check_offset(offset, DWORD_ALIGN)) { return -EINVAL; } /* BCM3450 requires the offset to be the register number */ buf[0] = offset/4; /* On the I2C bus, LS Byte should go first */ val = swab32(val); memcpy(&buf[1], (char*)&val, 4); if (i2c_master_send(client, buf, 5) == 5) { return 0; } return -1; }
/* Keep polling until the bcm63000 completes the I2C transaction or timeout */ static inline int wait_xfer_done(void) { int i, temp = 0; for (i = 0; i < xfer_timeout; i++) { temp = reg_read((uint32 *)&I2C->IICEnable); if (temp & I2C_IIC_NO_ACK) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "No Ack received \n"); return -1; } /* The xfer is complete and successful when INTRP is set and NOACK is not set */ if ((temp & I2C_IIC_INTRP) && !(temp & I2C_IIC_NO_ACK)) { return 0; } /* TBD: Call the schedule() */ udelay(1); } return -ETIMEDOUT; }
/* This function is called by i2c_probe */ static int bcm3450_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *client; int err = 0; #ifdef PROCFS_HOOKS struct proc_dir_entry *p; #endif BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) goto exit; if (!(pclient_data = kzalloc(sizeof(struct bcm3450_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } /* Setup the i2c client data */ client = &pclient_data->client; i2c_set_clientdata(client, pclient_data); client->addr = address; client->adapter = adapter; client->driver = &bcm3450_driver; client->flags = 0; strlcpy(client->name, "bcm3450", I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(client))) goto exit_kfree; #ifdef SYSFS_HOOKS /* Register sysfs hooks */ err = sysfs_create_group(&client->dev.kobj, &bcm3450_attr_group); if (err) goto exit_detach; #endif #ifdef PROCFS_HOOKS p = create_proc_entry(PROC_ENTRY_NAME1, 0, 0); if (!p) { BCM_LOG_ERROR(BCM_LOG_ID_I2C, "bcmlog: unable to create /proc/%s!\n", PROC_ENTRY_NAME1); err = -EIO; #ifdef SYSFS_HOOKS sysfs_remove_group(&client->dev.kobj, &bcm3450_attr_group); #endif goto exit_detach; } p->read_proc = b3450_proc_read; p->write_proc = b3450_proc_write; p->data = (void *)pclient_data; #ifdef MOCA_I2C_TEST p = create_proc_entry(PROC_ENTRY_NAME2, 0, 0); if (p) { p->proc_fops = &b3450Test_fops; } #endif #endif return 0; #if defined(SYSFS_HOOKS) || defined(PROCFS_HOOKS) exit_detach: i2c_detach_client(client); #endif exit_kfree: kfree(pclient_data); exit: return err; }
/* Write the given value to given bcm63000 register */ static inline void reg_write(uint32* offset, int val) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "reg_write: offset = %lx; val = %x\n", (long int)offset, val); *offset = val; }
/* Calls the appropriate function based on user command */ static int exec_command(const char *buf, size_t count, int fs_type) { #define MAX_ARGS 2 #define MAX_ARG_SIZE 32 int i, argc = 0, val = 0; char cmd; u8 offset; char arg[MAX_ARGS][MAX_ARG_SIZE]; #if 0 char temp_buf[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; #endif #ifdef PROCFS_HOOKS #define LOG_WR_KBUF_SIZE 128 char kbuf[LOG_WR_KBUF_SIZE]; if(fs_type == PROC_FS) { if ((count > LOG_WR_KBUF_SIZE-1) || (copy_from_user(kbuf, buf, count) != 0)) return -EFAULT; kbuf[count]=0; argc = sscanf(kbuf, "%c %s %s", &cmd, arg[0], arg[1]); } #endif #ifdef SYSFS_HOOKS if(fs_type == SYS_FS) argc = sscanf(buf, "%c %s %s", &cmd, arg[0], arg[1]); #endif if (argc <= 1) { BCM_LOG_NOTICE(BCM_LOG_ID_I2C, "Need at-least 2 arguments \n"); return -EFAULT; } for (i=0; i<MAX_ARGS; ++i) { arg[i][MAX_ARG_SIZE-1] = '\0'; } offset = (u8) simple_strtoul(arg[0], NULL, 0); if (argc == 3) val = (int) simple_strtoul(arg[1], NULL, 0); switch (cmd) { #if 0 case 'y': if (argc == 3) { if (val > 7) { BCM_LOG_INFO(BCM_LOG_ID_I2C, "Limiting byte count to 7 \n"); val = 7; } BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Write Byte Stream: offset = %x, " "count = %x \n", offset, val); for (i=0; i< val; i++) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "%x, ",temp_buf[i]); } temp_buf[0] = offset; bcm3450_write(temp_buf, val+1); } break; case 'z': if (argc == 3) { if (val > 8) { BCM_LOG_INFO(BCM_LOG_ID_I2C, "This test limits the byte stream" " count to 8 \n"); val = 8; } for (i=0; i< val; i++) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "%x, ",temp_buf[i]); } temp_buf[0] = offset; bcm3450_read(temp_buf, val); BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Read Byte Stream: offset = %x, " "count = %x \n", offset, val); for (i=0; i< val; i++) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "%x, ",temp_buf[i]); } BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "\n"); } break; #endif case 'b': if (argc == 3) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Write Byte: offset = %x, " "val = %x \n", offset, val); bcm3450_write_byte(offset, (u8)val); } else { val = bcm3450_read_byte(offset); BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Read Byte: offset = %x, " "val = %x \n", offset, val); } break; case 'w': if (argc == 3) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Write Word: offset = %x, " "val = %x \n", offset, val); bcm3450_write_word(offset, (u16)val); } else { val = bcm3450_read_word(offset); BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Read Word: offset = %x, " "val = %x \n", offset, val); } break; case 'd': if (argc == 3) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Write Register: offset = %x, " "val = %x \n", offset, val); bcm3450_write_reg(offset, val); } else { val = bcm3450_read_reg(offset); BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Read Register: offset = %x, " "val = %x \n", offset, val); } break; default: BCM_LOG_NOTICE(BCM_LOG_ID_I2C, "Invalid command. \n Valid commands: \n" " Write Reg: d offset val \n" " Read Reg: d offset \n" " Write Word: w offset val \n" " Read Word: w offset \n" " Write Byte: b offset val \n" " Read Byte: b offset \n" #if 0 " Write Bytes: y offset count \n" " Read Bytes: z offset count \n" #endif ); break; } return count; }
static int bcm3450_attach_adapter(struct i2c_adapter *adapter) { BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); return i2c_probe(adapter, &addr_data, bcm3450_detect); }
/* write followed by read without a stop in between */ static int i2c_write_then_read(struct i2c_msg *msgs, int fifo_len) { int j, ret = 0; u16 xfer_cnt; struct i2c_msg *p = &msgs[0], *q = &msgs[1]; uint32 flags; spin_lock_irqsave(&bcm_i2c_lock, flags); BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); /* Make sure IIC_Enable bit is zero before start of a new transaction. Note that a 0-1 transition of IIC_Enable is required to initiate an I2C bus transaction */ reg_write((uint32 *)&I2C->IICEnable, 0); /* Set the transfer counts for both the transactions */ xfer_cnt = (q->len << I2C_CNT_REG2_SHIFT) | p->len; /* Set the address, transfer count, and data transfer format */ i2c_rd_wr_common((u8)p->addr, xfer_cnt, I2C_CTL_REG_DTF_WRITE_AND_READ); /* Write the data */ if (fifo_len == 8) { for (j = 0; j < (p->len); j++) reg_write((uint32 *)&I2C->DataIn0 + j, p->buf[j]); } else { int num_dwords = ((p->len) + 3)/4; for (j = 0; j < num_dwords; j++) { #ifdef __LITTLE_ENDIAN reg_write((uint32 *)&I2C->DataIn0 + j, *((int *)&p->buf[j*4])); #else reg_write((uint32 *)&I2C->DataIn0 + j, swab32(*((int *)&p->buf[j*4]))); #endif } } /* Start the I2C transaction */ reg_write((uint32 *)&I2C->IICEnable, I2C_IIC_ENABLE); /* Wait for completion */ if (wait_xfer_done()) { ret = -EIO; goto end; } /* Read the data */ if (fifo_len == 8) { for (j = 0; j < (q->len); j++) q->buf[j] = (u8)reg_read((uint32 *)&I2C->DataOut0 + j); } else { int num_dwords = ((q->len) + 3)/4; for (j = 0; j < num_dwords; j++) { #ifdef __LITTLE_ENDIAN *((int *)&q->buf[j*4]) = reg_read((uint32 *)&I2C->DataOut0 + j); #else *((int *)&q->buf[j*4]) = swab32(reg_read((uint32 *)&I2C->DataOut0 + j)); #endif } } end: /* I2C bus transaction is complete, so set the IIC_Enable to zero */ reg_write((uint32 *)&I2C->IICEnable, 0); spin_unlock_irqrestore(&bcm_i2c_lock, flags); return ret; }
/* Write data of given length to the slave. Note that 2 or more transactions would be required on the bus if the length is more than the fifo_len */ static int i2c_write(struct i2c_msg *p, int fifo_len) { int i, j, ret = 0; u16 xfer_cnt; unsigned int len = p->len; unsigned char *buf = p->buf; unsigned char addr = p->addr; int loops = (len + (fifo_len - 1))/fifo_len; uint32 flags; BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "Entering the function %s \n", __FUNCTION__); spin_lock_irqsave(&bcm_i2c_lock, flags); /* Make sure IIC_Enable bit is zero before start of a new transaction. Note that a 0-1 transition of IIC_Enable is required to initiate an I2C bus transaction */ reg_write((uint32 *)&I2C->IICEnable, 0); for (i = 0; i < loops; i++) { /* Transfer size for the last iteration will be the remaining size */ xfer_cnt = (i==loops-1) ? (len - (i * fifo_len)) : fifo_len; /* Set the address, transfer count, and data transfer format */ i2c_rd_wr_common(addr, xfer_cnt, I2C_CTL_REG_DTF_WRITE); /* Write the data */ if (fifo_len == 8) { for (j = 0; j < xfer_cnt; j++) reg_write((uint32 *)&I2C->DataIn0 + j, buf[i * fifo_len + j]); } else { int num_dwords = (xfer_cnt + 3)/4; for (j = 0; j < num_dwords; j++) { #ifdef __LITTLE_ENDIAN reg_write((uint32 *)&I2C->DataIn0 + j, *((int *)&buf[i * fifo_len + j*4])); #else reg_write((uint32 *)&I2C->DataIn0 + j, swab32(*((int *)&buf[i * fifo_len + j*4]))); #endif } } /* Start the I2C transaction */ reg_write((uint32 *)&I2C->IICEnable, I2C_IIC_ENABLE); /* Wait for completion */ if (wait_xfer_done()) { ret = -EIO; goto end; } } end: /* I2C bus transaction is complete, so set the IIC_Enable to zero */ reg_write((uint32 *)&I2C->IICEnable, 0); spin_unlock_irqrestore(&bcm_i2c_lock, flags); return ret; }