|
From: Paul M. <le...@us...> - 2006-08-07 10:32:01
|
Update of /cvsroot/linuxsh/linux/drivers/i2c/busses In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv6267/drivers/i2c/busses Modified Files: Kconfig Makefile Added Files: i2c-sh7343.c i2c-sh7343.h Log Message: SH7343 i2c support. --- NEW FILE: i2c-sh7343.c --- /* i2c-sh7343.c - i2c bus adapter for Renesas' SH7343 i2c peripheral. Copyright (c) 2006 Carlos Munoz <ca...@ke...> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #undef DEBUG #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <asm/semaphore.h> #include "i2c-sh7343.h" /* Flag used to indicate transfer should be in poll mode. When called from atomic context. Note, caller will wait until transfer completes */ #define I2C_M_POLL 0x0080 static int rx_ack_high[MAX_CH] = {0, 0}; static unsigned long peripheral_clk = 27000000; static int fast_mode[MAX_CH] = {0, 0}; /* * msg_status_t: A message can be in one of these states: * * DONE: The message was sent/received successfully. * W_ADDR: The address of the device is being written. * W: The message is being written. * R-ADDR: The address of the device to read from * is being written. * R: The message is being read. * R1: The last byte of the message is being read. */ typedef enum { MSG_STATUS_DONE = 0, MSG_STATUS_W_ADDR, MSG_STATUS_W, MSG_STATUS_R_ADDR, MSG_STATUS_R, MSG_STATUS_R1, MSG_STATUS_ERR } msg_status_t; typedef struct { msg_status_t status; u_int8_t int_enb; u_int8_t addr[2]; struct i2c_msg *usr_msg; u_int32_t offset; u_int32_t len; } msg_t; typedef struct{ u_int32_t ch; struct semaphore sem; wait_queue_head_t wait; u_int8_t iccl; u_int8_t icch; msg_t msg; }ch_info_t; typedef struct { u_int32_t intevt; char *desc; irqreturn_t (*isr)(int, void *, struct pt_regs *); } irq_info_t; static ch_info_t i2c_info[MAX_CH]; static void activate_ch(ch_info_t *ch_info) { u_int32_t ch = ch_info->ch; /* Disable power down of the channel */ if(ch == 0) OUT32(MSTPCR1, IN32(MSTPCR1) & ~MSTPCR1_MSTP109); else OUT32(MSTPCR1, IN32(MSTPCR1) & ~MSTPCR1_MSTP108); /* Enable channel and configure rx ack */ OUT8(ICCR(ch), IN8(ICCR(ch)) | ICCR_ICE | (rx_ack_high[ch] ? ICCR_RACK : 0)); /* Mask all interrupts */ ch_info->msg.int_enb = 0; OUT8(ICIC(ch), 0x00 ); /* Set the clock */ OUT8(ICCL(ch), ch_info->iccl); OUT8(ICCH(ch), ch_info->icch); } static void deactivate_ch(ch_info_t *ch_info) { u_int32_t ch = ch_info->ch; /* Clear/disable interrupts */ ch_info->msg.int_enb = 0; OUT8(ICSR(ch), 0x00 ); OUT8(ICIC(ch), 0x00 ); /* Initialize channel */ OUT8(ICCR(ch), IN8(ICCR(ch)) & ~ICCR_ICE); /* Enable power down on the channel */ if(ch == 0) OUT32(MSTPCR1, IN32(MSTPCR1) | MSTPCR1_MSTP109); else OUT32(MSTPCR1, IN32(MSTPCR1) | MSTPCR1_MSTP108); } void restart_ch(ch_info_t *ch_info) { u_int32_t ch = ch_info->ch; /* Initialize channel registers */ OUT8(ICCR(ch), IN8(ICCR(ch)) & ~ICCR_ICE); /* Enable channel and configure rx ack */ OUT8(ICCR(ch), IN8(ICCR(ch)) | ICCR_ICE | (rx_ack_high[ch] ? ICCR_RACK : 0)); /* Set the clock */ OUT8(ICCL(ch), ch_info->iccl); OUT8(ICCH(ch), ch_info->icch); } #if DEBUG static void dump_msg(struct i2c_msg *msg) { int i; static u_int8_t buf[1028]; int len = 0; printk(KERN_ERR "Address=%04x flags=%04x len=%04x\n", msg->addr, msg->flags, msg->len); if (!(msg->flags & I2C_M_RD)) { for (i = 0; i < msg->len; i++) { len += snprintf(buf + len, 1028 - len, (i % 0x10) ? "%02x\n" : "%02x ", msg->buf[i]); } printk(KERN_ERR "%s\n", buf); } } #endif u32 i2c_sh7343_func(struct i2c_adapter *adapter) { pr_debug("Functionality query"); return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; } static void write_data(ch_info_t *ch_info) { u_int8_t ch = ch_info->ch; msg_t *msg = &ch_info->msg; /* Write the data */ OUT8(ICDR(ch), msg->usr_msg->buf[msg->offset++]); if (msg->offset == msg->len) { /* Issue a stop condition */ OUT8(ICCR(ch), ICCR_ICE | ICCR_TRS); /* Disable the dte interrupt */ msg->int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); msg->status = MSG_STATUS_DONE; /* Notify the waiting process the message was sent */ wake_up_interruptible(&ch_info->wait); } } static void read_data(ch_info_t *ch_info) { u_int8_t ch = ch_info->ch; msg_t *msg = &ch_info->msg; u_int8_t dummy; /* Check if we are receiving only 1 byte */ if (msg->status == MSG_STATUS_R1) { /* Disable wait interrpt */ msg->int_enb &= ~ICSR_WAIT; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_DTEE)); /* Read the data */ msg->usr_msg->buf[msg->offset++] = IN8(ICDR(ch)); msg->status = MSG_STATUS_DONE; /* Notify the waiting process the message was sent */ wake_up_interruptible(&ch_info->wait); } else { if (msg->usr_msg->len - msg->offset > 0) { /* Disable dte interrupt */ msg->int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); /* Read the data */ msg->usr_msg->buf[msg->offset++] = IN8(ICDR(ch)); /* Check if there is only 1 byte left to read */ if (msg->usr_msg->len - msg->offset == 1) msg->status = MSG_STATUS_R1; } else { /* After read end. End condition set */ dummy = IN8(ICDR(ch)); msg->status = MSG_STATUS_DONE; /* Notify the waiting process the message was sent */ wake_up_interruptible(&ch_info->wait); } } } static void write_addr(ch_info_t *ch_info) { u_int8_t ch = ch_info->ch; msg_t *msg = &ch_info->msg; /* Wrte the slave address */ OUT8(ICDR(ch), msg->addr[msg->offset++]); if (msg->offset == msg->len) { msg->offset = 0; msg->len = msg->usr_msg->len; msg->status = MSG_STATUS_W; } } static void read_addr(ch_info_t *ch_info) { u_int8_t ch = ch_info->ch; msg_t *msg = &ch_info->msg; /* 10 bit addresses are different */ if (msg->usr_msg->flags == I2C_M_TEN) { if (msg->offset == 0) { OUT8(ICDR(ch), msg->addr[msg->offset++]); } else if (msg->offset == 1) { OUT8(ICDR(ch), msg->addr[msg->offset++]); /* Generate a resend condition */ OUT8(ICCR(ch), ICCR_ICE | ICCR_TRS | ICCR_BBSY); } else { /* Enable the wait interrupt */ msg->int_enb |= ICSR_WAIT; OUT8(ICIC(ch), IN8(ICIC(ch)) | ICIC_WAITE ); /* Disable the dte interrupt */ msg->int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); /* Slave address write */ OUT8(ICDR(ch), msg->addr[0]); } } else { /* 7 bit address type */ /* Enable the wait interrupt */ msg->int_enb |= ICSR_WAIT; OUT8(ICIC(ch), IN8(ICIC(ch)) | ICIC_WAITE ); /* Disable the dte interrupt */ msg->int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); /* Slave address write */ OUT8(ICDR(ch), msg->addr[0]); } } static irqreturn_t i2c_sh7343_wait_isr(int irq, void *dev_id, struct pt_regs *regs) { u_int32_t ch = (u_int32_t)dev_id; ch_info_t *ch_info = &i2c_info[ch]; msg_t *msg = &ch_info->msg; /* Read slave address output */ if (msg->status == MSG_STATUS_R_ADDR) { if (msg->usr_msg->len == 1) msg->status = MSG_STATUS_R1; else msg->status = MSG_STATUS_R; /* Send/receive change */ OUT8(ICCR(ch), ICCR_ICE | ICCR_SCP); msg->offset = 0; } else if (msg->status == MSG_STATUS_R1) { /* Enable dte interrupt */ msg->int_enb |= ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) | ICIC_DTEE); /* Set stop condition */ OUT8(ICCR(ch), ICCR_ICE | ICCR_RACK); } else if (msg->status == MSG_STATUS_R) { /* Check if dte is set */ if ((IN8(ICSR(ch)) & ICSR_DTE) == 1) { /* Read one byte of data */ msg->usr_msg->buf[msg->offset++] = IN8(ICDR(ch)); /* Check if there is only 1 byte left to read */ if (msg->usr_msg->len - msg->offset == 1) { msg->status = MSG_STATUS_R1; /* Set stop condition */ OUT8(ICCR(ch), ICCR_ICE | ICCR_RACK); } } /* Enable dte interrupt */ msg->int_enb |= ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) | ICIC_DTEE); /* Check if there is no more data to read */ if (msg->usr_msg->len - msg->offset == 0) { /* Set stop condition */ OUT8(ICCR(ch), ICCR_ICE | ICCR_RACK); } } /* Clear wait interrupt */ OUT8(ICSR(ch), IN8(ICSR(ch)) & (ICSR_AL | ICSR_TACK | ICSR_DTE)); return IRQ_HANDLED; } static irqreturn_t i2c_sh7343_dte_isr(int irq, void *dev_id, struct pt_regs *regs) { u_int32_t ch = (u_int32_t)dev_id; ch_info_t *ch_info = &i2c_info[ch]; /* Write the message */ if (ch_info->msg.status == MSG_STATUS_W) { /* Disable the wait interrupt */ ch_info->msg.int_enb &= ~ICSR_WAIT; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_DTEE)); write_data(ch_info); } /* Read the message */ else if (ch_info->msg.status == MSG_STATUS_R || ch_info->msg.status == MSG_STATUS_R1) { read_data(ch_info); } /* Write the slave address */ else if (ch_info->msg.status == MSG_STATUS_W_ADDR) { /* Disable the wait interrupt */ ch_info->msg.int_enb &= ~ICSR_WAIT; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_DTEE)); write_addr(ch_info); } /* Read slave address output */ else if (ch_info->msg.status == MSG_STATUS_R_ADDR) { /* Disable the wait interrupt */ ch_info->msg.int_enb &= ~ICSR_WAIT; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_DTEE)); read_addr(ch_info); } else{ /* Disable the dte interrupt */ ch_info->msg.int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); } return IRQ_HANDLED; } static irqreturn_t i2c_sh7343_tack_isr(int irq, void *dev_id, struct pt_regs *regs) { u_int32_t ch = (u_int32_t)dev_id; ch_info_t *ch_info = &i2c_info[ch]; ch_info->msg.status = MSG_STATUS_ERR; /* Clear TACK interrupt */ OUT8(ICSR(ch), IN8(ICSR(ch)) & ~ICSR_TACK); /* Disable the dte interrupt */ ch_info->msg.int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); /* Notify the waiting process the transmition stopped */ wake_up_interruptible(&ch_info->wait); return IRQ_HANDLED; } static irqreturn_t i2c_sh7343_al_isr(int irq, void *dev_id, struct pt_regs *regs) { u_int32_t ch = (u_int32_t)dev_id; ch_info_t *ch_info = &i2c_info[ch]; ch_info->msg.status = MSG_STATUS_ERR; /* Clear AL interrupt */ OUT8(ICSR(ch), IN8(ICSR(ch)) & ~ICSR_AL); /* Disable the dte interrupt */ ch_info->msg.int_enb &= ~ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) & (ICIC_ALE | ICIC_TACKE | ICIC_WAITE)); /* Notify the waiting process the transmition stopped */ wake_up_interruptible(&ch_info->wait); return IRQ_HANDLED; } static irq_info_t irq_info[MAX_CH][INT_PER_CH] = { {{IIC0_ALI_IRQ, "I2C al-0", i2c_sh7343_al_isr}, {IIC0_TACKI_IRQ, "I2C tack-0", i2c_sh7343_tack_isr}, {IIC0_WAITI_IRQ, "I2C wait-0", i2c_sh7343_wait_isr}, {IIC0_DTEI_IRQ, "I2C dte-0", i2c_sh7343_dte_isr}}, {{IIC1_ALI_IRQ, "I2C al-1", i2c_sh7343_al_isr}, {IIC1_TACKI_IRQ, "I2C tack-1", i2c_sh7343_tack_isr}, {IIC1_WAITI_IRQ, "I2C wait-1", i2c_sh7343_wait_isr}, {IIC1_DTEI_IRQ, "I2C dte-1", i2c_sh7343_dte_isr}} }; static int start_ch(ch_info_t *ch_info, struct i2c_msg *usr_msg) { u_int32_t ch = ch_info->ch; int i; u_int8_t val; /* Wait for last transfer to end */ for (i = BUSYCHECK_TIMEOUT; i > 0; i--) { val = IN8(ICSR(ch)); if (!(val & ICSR_BUSY) && val & ICSR_SCLM && val & ICSR_SDAM) break; } if (i == 0) { pr_debug("Device still busy, timeout"); return -EBUSY; } /* Initialize channel registers */ restart_ch(ch_info); /* Set up the address */ if (usr_msg->flags & I2C_M_RD) { val = 1; ch_info->msg.status = MSG_STATUS_R_ADDR; } else { val = 0; ch_info->msg.status = MSG_STATUS_W_ADDR; } if (usr_msg->flags & I2C_M_TEN) { ch_info->msg.addr[0] = (u_int8_t)(((usr_msg->addr >> 7) & 6) | 0xf0 | val); ch_info->msg.addr[1] = (u_int8_t)(usr_msg->addr & 0xff); ch_info->msg.len = 2; } else { ch_info->msg.addr[0] = (u_int8_t)((usr_msg->addr << 1) | val); ch_info->msg.len = 1; } ch_info->msg.offset = 0; ch_info->msg.usr_msg = usr_msg; /* When in poll mode, remove the isrs. We need to do this because the i2c wait interrupt must be enabled for the wait interrupt request to be set. We remove the isrs and leave the i2c interrupts enabled. */ if (usr_msg->flags & I2C_M_POLL) { for (i = 0; i < INT_PER_CH; i++) free_irq(irq_info[ch][i].intevt, (void *)ch); } /* Enable all interrupts except wait */ ch_info->msg.int_enb = ICSR_AL | ICSR_TACK | ICSR_DTE; OUT8(ICIC(ch), IN8(ICIC(ch)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE); return 0; } static msg_status_t end_ch(ch_info_t *ch_info) { u_int32_t ch = ch_info->ch; int i; u_int8_t val; int rc; for (i = BUSYCHECK_TIMEOUT; i > 0; i--) { /* If there was an error, stop */ if (ch_info->msg.status != MSG_STATUS_DONE) { break; } else { /* Wait until the transfer ends */ val = IN8(ICSR(ch)); if (!(val & ICSR_BUSY) && val & ICSR_SCLM && val & ICSR_SDAM) { break; } } } if (i == 0 || ch_info->msg.status != MSG_STATUS_DONE) { pr_debug("Device could not complete last event, timeout i=%d", i); ch_info->msg.status = MSG_STATUS_ERR; restart_ch(ch_info); } /* Mask all interrupts */ ch_info->msg.int_enb = 0; OUT8(ICIC(ch), 0x00 ); /* When in poll mode, re-insert the isrs */ if (ch_info->msg.usr_msg->flags & I2C_M_POLL) { for (i = 0; i < INT_PER_CH; i++) { if ((rc = request_irq(irq_info[ch][i].intevt, irq_info[ch][i].isr, SA_INTERRUPT, irq_info[ch][i].desc, (void *)ch))) { pr_debug("request_irq() failed irq=%d, err=%d", irq_info[ch][i].intevt, rc); ch_info->msg.status = MSG_STATUS_ERR; break; } } } return ch_info->msg.status; } static int i2c_sh7343_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { int i; int j; ch_info_t *ch_info; u_int32_t ch; struct i2c_msg *msg; int err = 0; u_int8_t icsr; pr_debug("Transfer request: num=%d", num); /* Validate parameters */ if (!adapter || !msgs || !num) return -EINVAL; /* Point to the right channel info */ ch_info = adapter->algo_data; ch = ch_info->ch; /* Serialize access to the channel */ down_interruptible(&ch_info->sem); /* Initialize the channel */ activate_ch(ch_info); /* Process all messages */ for (i = 0; i < num; i++) { msg = &msgs[i]; if (!msg->len || !msg->buf) continue; #if DEBUG dump_msg(msg); #endif if ((err = start_ch(ch_info, msg))) break; /* Kick start the write/read (DTE interrupts will occur) */ OUT8(ICCR(ch), ICCR_ICE | ICCR_TRS | ICCR_BBSY); /* Check if poll mode was requested */ if (msg->flags & I2C_M_POLL) { for (j = 0; j < POLL_EVENT_TIMEOUT; j++) { if (ch_info->msg.status == MSG_STATUS_DONE || ch_info->msg.status == MSG_STATUS_ERR) break; /* Monitor the interrupt request bits and call the corresponding isr */ icsr = IN8(ICSR(ch)); if (icsr & ICSR_AL && ch_info->msg.int_enb & ICSR_AL) { i2c_sh7343_al_isr(0, (void *)ch, NULL); } if (icsr & ICSR_TACK && ch_info->msg.int_enb & ICSR_TACK) { i2c_sh7343_tack_isr(0, (void *)ch, NULL); } if (icsr & ICSR_WAIT && ch_info->msg.int_enb & ICSR_WAIT) { i2c_sh7343_wait_isr(0, (void *)ch, NULL); } if (icsr & ICSR_DTE && ch_info->msg.int_enb & ICSR_DTE) { i2c_sh7343_dte_isr(0, (void *)ch, NULL); } } } else { /* Sleep until done. The isr will wake us up when the transfer is done */ if (!wait_event_interruptible_timeout(ch_info->wait, ch_info->msg.status == MSG_STATUS_DONE || ch_info->msg.status == MSG_STATUS_ERR, WAIT_TIMEOUT)) { ch_info->msg.status = MSG_STATUS_ERR; pr_debug("Transfer request timed out waiting to " "complete"); } } /* Make sure the write was successfull */ if (end_ch(ch_info) != MSG_STATUS_DONE) { err = -EIO; break; } } /* Put i2c peripheral in power down mode */ deactivate_ch(ch_info); up(&ch_info->sem); if (!err) err = num; return err; } static struct i2c_algorithm sh7343_algo = { .functionality = i2c_sh7343_func, .master_xfer = i2c_sh7343_xfer, }; static struct i2c_adapter sh7343_adapter[MAX_CH] = { {.owner = THIS_MODULE, .class = I2C_CLASS_SOUND, .algo = &sh7343_algo, .algo_data = &i2c_info[0], .name = "I2C SH7343 adapter channel 0" }, {.owner = THIS_MODULE, .class = I2C_CLASS_ALL, .algo = &sh7343_algo, .algo_data = &i2c_info[1], .name = "I2C SH7343 adapter channel 1" } }; /* This is a wrapper for kernel modules that need to call the transfer function directly. This function can not be called in atomic context since it blocks */ int i2c_sh7343_xfer_mod(int ch, struct i2c_msg *msgs, int num) { struct i2c_adapter *adapter; adapter = ch == 0 ? &sh7343_adapter[0] : ch == 1 ? &sh7343_adapter[1] : NULL; return i2c_sh7343_xfer(adapter, msgs, num); } /* This is a wrapper for kernel modules that need to call the transfer function directly. It can be called in atomic context since it polls the hardware until the transfer completes. */ int i2c_sh7343_xfer_mod_poll(int ch, struct i2c_msg *msgs, int num) { struct i2c_adapter *adapter; int i; adapter = ch == 0 ? &sh7343_adapter[0] : ch == 1 ? &sh7343_adapter[1] : NULL; /* Set the poll flag on all messages */ for (i = 0; i < num; i++) msgs[i].flags |= I2C_M_POLL; return i2c_sh7343_xfer(adapter, msgs, num); } static int __init i2c_sh7343_init(void) { int i, j; u_int32_t num; u_int32_t denom; u_int32_t tmp; int rc = 0; printk(KERN_INFO "i2c-sh7343: "); for (i = 0; i < MAX_CH; i++) { i2c_info[i].ch = i; init_MUTEX(&i2c_info[i].sem); init_waitqueue_head(&i2c_info[i].wait); /* Calculate the value for iccl. From the data sheet: iccl = (p clock ÷ transfer rate) × (L ÷ (L + H)) where L and H are the SCL low/high ratio (5/4 in this case). We also round off the result */ num = peripheral_clk * 5; denom = fast_mode[i] ? FAST_SPEED : NORMAL_SPEED * 9; tmp = num * 10 / denom; if (tmp % 10 >= 5) i2c_info[i].iccl = (u_int8_t)((num/denom) + 1); else i2c_info[i].iccl = (u_int8_t)(num/denom); /* Calculate the value for icch. From the data sheet: icch = (p clock ÷ transfer rate) × (H ÷ (L + H)) */ num = peripheral_clk * 4; tmp = num * 10 / denom; if (tmp % 10 >= 5) i2c_info[i].icch = (u_int8_t)((num/denom) + 1); else i2c_info[i].icch = (u_int8_t)(num/denom); /* Power down the i2c peripheral until is needed */ deactivate_ch(&i2c_info[i]); } /* Register all interrupts, 4 per channel */ for (i = 0; i < MAX_CH; i++) { for (j = 0; j < INT_PER_CH; j++) { if ((rc = request_irq(irq_info[i][j].intevt, irq_info[i][j].isr, SA_INTERRUPT, irq_info[i][j].desc, (void *)i))) { pr_debug("request_irq() failed irq=%d, err=%d", irq_info[i][j].intevt, rc); for (j -= 1; j >= 0; j--) { free_irq(irq_info[i][j].intevt, (void *)i); } for (i -= 1; i >= 0; i--) { for (j = 0; j < INT_PER_CH; j++) { free_irq(irq_info[i][j].intevt, (void *)i); } } goto fail; } } } for (i = 0; i < MAX_CH; i++) { if ((rc = i2c_add_adapter(&sh7343_adapter[i]))) { pr_debug("i2c_add_adapter() failed err=%d", rc); for (i -= 1; i >= 0; i--) { i2c_del_adapter(&sh7343_adapter[i]); } for (i = 0; i < MAX_CH; i++) { for (j = 0; j < INT_PER_CH; j++) { free_irq(irq_info[i][j].intevt, (void *)i); } } goto fail; } } printk("initialized.\n"); return 0; fail: printk("failed to initialize.\n"); return rc; } static void __exit i2c_sh7343_exit(void) { int i, j; for (i = 0; i < MAX_CH; i++) { i2c_del_adapter(&sh7343_adapter[i]); } for (i = 0; i < MAX_CH; i++) { for (j = 0; j < INT_PER_CH; j++) { free_irq(irq_info[i][j].intevt, (void *)i); } } printk(KERN_INFO "i2c-sh7343: exited\n"); } EXPORT_SYMBOL(i2c_sh7343_xfer_mod); EXPORT_SYMBOL(i2c_sh7343_xfer_mod_poll); EXPORT_SYMBOL(i2c_sh7343_func); module_param_array(rx_ack_high, bool, NULL, 0); MODULE_PARM_DESC(rx_ack_high, "Use SDA high to ack received data"); module_param(peripheral_clk, ulong, 0); MODULE_PARM_DESC(peripheral_clk, "Clock rate of external peripheral clock"); module_param_array(fast_mode, bool, NULL, 0); MODULE_PARM_DESC(fast_mode, "Force fast mode (400 Kbs)"); MODULE_AUTHOR("Carlos Munoz <ca...@ke...>"); MODULE_DESCRIPTION("I2C SH7343 driver"); MODULE_LICENSE("GPL"); module_init(i2c_sh7343_init); module_exit(i2c_sh7343_exit); --- NEW FILE: i2c-sh7343.h --- /* i2c-sh7343.h - i2c bus adapter for Renesas' SH7343 i2c peripheral. Copyright (c) 2006 Carlos Munoz <ca...@ke...> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef I2C_SH7343_H #define I2C_SH7343_H #define MAX_CH 2 #define NORMAL_SPEED 100000 #define FAST_SPEED 400000 /* Four interrupts: al, tack, dte and wait */ #define INT_PER_CH 4 /* How long to wait for the last event to complete (about 100ms) */ #define BUSYCHECK_TIMEOUT 150000 /* How long to wait for an event to complete in poll mode */ #define POLL_EVENT_TIMEOUT (BUSYCHECK_TIMEOUT * 5) /* How long to wait for the transfer to complete (500 msec) */ #define WAIT_TIMEOUT (500 / (1000 / HZ)) /* Register offsets */ #define I2C_BASE 0xa4470000 #define ICDR(ch) (I2C_BASE + 0x00 + ch * 0x2e0000) #define ICCR(ch) (I2C_BASE + 0x04 + ch * 0x2e0000) #define ICSR(ch) (I2C_BASE + 0x08 + ch * 0x2e0000) #define ICIC(ch) (I2C_BASE + 0x0c + ch * 0x2e0000) #define ICCL(ch) (I2C_BASE + 0x10 + ch * 0x2e0000) #define ICCH(ch) (I2C_BASE + 0x14 + ch * 0x2e0000) /* Register access */ #define IN8(addr) (*((volatile u_int8_t *)(addr))) #define IN16(addr) (*((volatile u_int16_t *)(addr))) #define IN32(addr) (*((volatile u_int32_t *)(addr))) #define OUT8(addr, val) (*((volatile u_int8_t *)(addr)) = (val)) #define OUT16(addr, val) (*((volatile u_int16_t *)(addr)) = (val)) #define OUT32(addr, val) (*((volatile u_int32_t *)(addr)) = (val)) /* Register bits */ #define ICCR_ICE 0x80 #define ICCR_RACK 0x40 #define ICCR_TRS 0x10 #define ICCR_BBSY 0x04 #define ICCR_SCP 0x01 #define ICSR_SCLM 0x80 #define ICSR_SDAM 0x40 #define ICSR_BUSY 0x10 #define ICSR_AL 0x08 #define ICSR_TACK 0x04 #define ICSR_WAIT 0x02 #define ICSR_DTE 0x01 #define ICIC_ALE 0x08 #define ICIC_TACKE 0x04 #define ICIC_WAITE 0x02 #define ICIC_DTEE 0x01 /* Interrupt event codes */ #define AL_INTEVT_CH0 0x0e00 #define TACK_INTEVT_CH0 0x0e20 #define WAIT_INTEVT_CH0 0x0e40 #define DTE_INT_EVT_CH0 0x0e60 #define AL_INTEVT_CH1 0x0780 #define TACK_INTEVT_CH1 0x07a0 #define WAIT_INTEVT_CH1 0x07c0 #define DTE_INT_EVT_CH1 0x07e0 /* Power down module */ #define MSTPCR1 0xa4150034 #define MSTPCR1_MSTP108 0x00000100 #define MSTPCR1_MSTP109 0x00000200 #endif /* I2C_SH7343_H */ Index: Kconfig =================================================================== RCS file: /cvsroot/linuxsh/linux/drivers/i2c/busses/Kconfig,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- Kconfig 5 Jul 2006 08:46:48 -0000 1.12 +++ Kconfig 7 Aug 2006 10:31:50 -0000 1.13 @@ -527,4 +527,14 @@ This driver can also be built as a module. If so, the module will be called i2c-mv64xxx. +config I2C_SH7343 + tristate "Renesas sh7343 I2C Controller" + depends on I2C && SUPERH && CPU_SUBTYPE_SH7343 + help + If you say yes to this option, support will be included for the + built-in I2C interface on the Renesas SH7343 processor. + + This driver can also be built as a module. If so, the module + will be called i2c-sh7343. + endmenu Index: Makefile =================================================================== RCS file: /cvsroot/linuxsh/linux/drivers/i2c/busses/Makefile,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- Makefile 27 Mar 2006 21:06:14 -0000 1.9 +++ Makefile 7 Aug 2006 10:31:50 -0000 1.10 @@ -43,6 +43,7 @@ obj-$(CONFIG_I2C_VOYAGER) += i2c-voyager.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_SH7343) += i2c-sh7343.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG |