* [PATCH] I2C: SiByte: Convert the driver to make use of interrupts @ 2010-12-06 6:38 Matt Turner [not found] ` <1291617494-18430-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2010-12-06 6:38 UTC (permalink / raw) To: Jean Delvare Cc: linux-i2c, linux-mips, Ralf Baechle, Maciej W. Rozycki, Matt Turner From: Maciej W. Rozycki <macro@linux-mips.org> This is a rewrite of large parts of the driver mainly so that it uses SMBus interrupts to offload the CPU from busy-waiting on status inputs. As a part of the overhaul of the init and exit calls, all accesses to the hardware got converted to use accessory functions via an ioremap() cookie. Minimally rebased by Matt Turner. Tested-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Matt Turner <mattst88@gmail.com> --- This patch was originally sent in May 2008 [1], but appears to have been lost. I believe this patch depends on [PATCH 1/3] RTC: SMBus support for the M41T80, etc. driver Please review the change in return values (search for ENXIO). I wasn't entirely sure how this code should look. (The code the original patch was against just returned -1 on error. See 102b59c6d6d30fb6560177fd1ae8a34c4c163897). Please apply if acceptable. [1] http://lists.lm-sensors.org/pipermail/i2c/2008-May/003638.html drivers/i2c/busses/i2c-sibyte.c | 278 +++++++++++++++++++++++++++++---------- 1 files changed, 208 insertions(+), 70 deletions(-) diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 0fe505d..283747c 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -2,6 +2,7 @@ * Copyright (C) 2004 Steven J. Hill * Copyright (C) 2001,2002,2003 Broadcom Corporation * Copyright (C) 1995-2000 Simon G. Vogl + * Copyright (C) 2008 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,104 +19,159 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/errno.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/param.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/wait.h> #include <linux/io.h> +#include <asm/sibyte/sb1250_int.h> #include <asm/sibyte/sb1250_regs.h> #include <asm/sibyte/sb1250_smbus.h> struct i2c_algo_sibyte_data { - void *data; /* private data */ - int bus; /* which bus */ - void *reg_base; /* CSR base */ + wait_queue_head_t wait; /* IRQ queue */ + void __iomem *csr; /* mapped CSR handle */ + phys_t base; /* physical CSR base */ + char *name; /* IRQ handler name */ + spinlock_t lock; /* atomiser */ + int irq; /* IRQ line */ + int status; /* IRQ status */ }; -/* ----- global defines ----------------------------------------------- */ -#define SMB_CSR(a,r) ((long)(a->reg_base + r)) +static irqreturn_t i2c_sibyte_interrupt(int irq, void *dev_id) +{ + struct i2c_adapter *i2c_adap = dev_id; + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + u8 status; + + /* + * Ugh, no way to detect the finish interrupt, + * but if busy it is obviously not one. + */ + status = __raw_readq(csr + R_SMB_STATUS); + if ((status & (M_SMB_ERROR | M_SMB_BUSY)) == M_SMB_BUSY) + return IRQ_NONE; -static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) + /* + * Clear the error interrupt (write 1 to clear); + * the finish interrupt was cleared by the read above. + */ + __raw_writeq(status, csr + R_SMB_STATUS); + + /* Post the status. */ + spin_lock_irq(&adap->lock); + adap->status = status & (M_SMB_ERROR_TYPE | M_SMB_ERROR | M_SMB_BUSY); + wake_up(&adap->wait); + spin_unlock_irq(&adap->lock); + + return IRQ_HANDLED; +} + +static s32 i2c_sibyte_smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, + unsigned short cflags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) { struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + unsigned long flags; int data_bytes = 0; int error; - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; + spin_lock_irqsave(&adap->lock, flags); + + if (adap->status < 0) { + error = -EIO; + goto out_unlock; + } switch (size) { case I2C_SMBUS_QUICK: - csr_out32((V_SMB_ADDR(addr) | - (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | - V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | + (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | + V_SMB_TT_QUICKCMD, + csr + R_SMB_START); break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE, + csr + R_SMB_START); data_bytes = 1; } else { - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE, + csr + R_SMB_START); } break; case I2C_SMBUS_BYTE_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE, + csr + R_SMB_START); data_bytes = 1; } else { - csr_out32(V_SMB_LB(data->byte), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_LB(data->byte), csr + R_SMB_DATA); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, + csr + R_SMB_START); } break; case I2C_SMBUS_WORD_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE, + csr + R_SMB_START); data_bytes = 2; } else { - csr_out32(V_SMB_LB(data->word & 0xff), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32(V_SMB_MB(data->word >> 8), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_LB(data->word & 0xff), + csr + R_SMB_DATA); + __raw_writeq(V_SMB_MB(data->word >> 8), + csr + R_SMB_DATA); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, + csr + R_SMB_START); } break; default: - return -EOPNOTSUPP; + error = -EOPNOTSUPP; + goto out_unlock; } + mmiowb(); + __raw_readq(csr + R_SMB_START); + adap->status = -1; + + spin_unlock_irqrestore(&adap->lock, flags); + + wait_event_timeout(adap->wait, (adap->status >= 0), HZ); - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; + spin_lock_irqsave(&adap->lock, flags); - error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); - if (error & M_SMB_ERROR) { - /* Clear error bit by writing a 1 */ - csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); - return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO; + if (adap->status < 0 || (adap->status & (M_SMB_ERROR | M_SMB_BUSY))) { + error = -EIO; + goto out_unlock; } if (data_bytes == 1) - data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; + data->byte = __raw_readq(csr + R_SMB_DATA) & 0xff; if (data_bytes == 2) - data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; + data->word = __raw_readq(csr + R_SMB_DATA) & 0xffff; - return 0; + error = 0; + +out_unlock: + spin_unlock_irqrestore(&adap->lock, flags); + + return error; } -static u32 bit_func(struct i2c_adapter *adap) +static u32 i2c_sibyte_bit_func(struct i2c_adapter *adap) { return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); @@ -125,8 +181,8 @@ static u32 bit_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static const struct i2c_algorithm i2c_sibyte_algo = { - .smbus_xfer = smbus_xfer, - .functionality = bit_func, + .smbus_xfer = i2c_sibyte_smbus_xfer, + .functionality = i2c_sibyte_bit_func, }; /* @@ -135,37 +191,108 @@ static const struct i2c_algorithm i2c_sibyte_algo = { static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) { struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr; + int err; - /* Register new adapter to i2c module... */ - i2c_adap->algo = &i2c_sibyte_algo; + adap->status = 0; + init_waitqueue_head(&adap->wait); + spin_lock_init(&adap->lock); + + csr = ioremap(adap->base, R_SMB_PEC + SMB_REGISTER_SPACING); + if (!csr) { + err = -ENOMEM; + goto out; + } + adap->csr = csr; /* Set the requested frequency. */ - csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); - csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); + __raw_writeq(speed, csr + R_SMB_FREQ); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + err = request_irq(adap->irq, i2c_sibyte_interrupt, IRQF_SHARED, + adap->name, i2c_adap); + if (err < 0) + goto out_unmap; + + /* Enable finish and error interrupts. */ + __raw_writeq(M_SMB_FINISH_INTR | M_SMB_ERR_INTR, csr + R_SMB_CONTROL); + + /* Register new adapter to i2c module... */ + err = i2c_add_numbered_adapter(i2c_adap); + if (err < 0) + goto out_unirq; - return i2c_add_numbered_adapter(i2c_adap); + return 0; + +out_unirq: + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + free_irq(adap->irq, i2c_adap); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); +out_unmap: + iounmap(csr); +out: + return err; } +static void i2c_sibyte_remove_bus(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + + i2c_del_adapter(i2c_adap); + + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + free_irq(adap->irq, i2c_adap); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); + + iounmap(csr); +} -static struct i2c_algo_sibyte_data sibyte_board_data[2] = { - { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, - { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } +static struct i2c_algo_sibyte_data i2c_sibyte_board_data[2] = { + { + .name = "sb1250-smbus-0", + .base = A_SMB_0, + .irq = K_INT_SMB_0, + }, + { + .name = "sb1250-smbus-1", + .base = A_SMB_1, + .irq = K_INT_SMB_1, + } }; -static struct i2c_adapter sibyte_board_adapter[2] = { +static struct i2c_adapter i2c_sibyte_board_adapter[2] = { { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = NULL, - .algo_data = &sibyte_board_data[0], + .algo = &i2c_sibyte_algo, + .algo_data = &i2c_sibyte_board_data[0], .nr = 0, .name = "SiByte SMBus 0", }, { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = NULL, - .algo_data = &sibyte_board_data[1], + .algo = &i2c_sibyte_algo, + .algo_data = &i2c_sibyte_board_data[1], .nr = 1, .name = "SiByte SMBus 1", }, @@ -173,21 +300,32 @@ static struct i2c_adapter sibyte_board_adapter[2] = { static int __init i2c_sibyte_init(void) { + int err; + pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n"); - if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0) - return -ENODEV; - if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], - K_SMB_FREQ_400KHZ) < 0) { - i2c_del_adapter(&sibyte_board_adapter[0]); - return -ENODEV; - } + + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[0], + K_SMB_FREQ_100KHZ); + if (err < 0) + goto out; + + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[1], + K_SMB_FREQ_400KHZ); + if (err < 0) + goto out_remove; + return 0; + +out_remove: + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); +out: + return err; } static void __exit i2c_sibyte_exit(void) { - i2c_del_adapter(&sibyte_board_adapter[0]); - i2c_del_adapter(&sibyte_board_adapter[1]); + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[1]); + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); } module_init(i2c_sibyte_init); -- 1.7.2.2 ^ permalink raw reply related [flat|nested] 30+ messages in thread
[parent not found: <1291617494-18430-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <1291617494-18430-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2010-12-06 14:59 ` Guenter Roeck 2010-12-06 17:30 ` Guenter Roeck 2010-12-07 6:23 ` Guenter Roeck 2 siblings, 0 replies; 30+ messages in thread From: Guenter Roeck @ 2010-12-06 14:59 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle, Maciej W. Rozycki On Mon, Dec 06, 2010 at 01:38:14AM -0500, Matt Turner wrote: > From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > > This is a rewrite of large parts of the driver mainly so that it uses > SMBus interrupts to offload the CPU from busy-waiting on status inputs. > As a part of the overhaul of the init and exit calls, all accesses to the > hardware got converted to use accessory functions via an ioremap() cookie. > > Minimally rebased by Matt Turner. > > Tested-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > --- > This patch was originally sent in May 2008 [1], but appears to have been lost. > > I believe this patch depends on > [PATCH 1/3] RTC: SMBus support for the M41T80, etc. driver > > Please review the change in return values (search for ENXIO). I wasn't entirely > sure how this code should look. (The code the original patch was against just > returned -1 on error. See 102b59c6d6d30fb6560177fd1ae8a34c4c163897). Please > apply if acceptable. > > [1] http://lists.lm-sensors.org/pipermail/i2c/2008-May/003638.html > > drivers/i2c/busses/i2c-sibyte.c | 278 +++++++++++++++++++++++++++++---------- > 1 files changed, 208 insertions(+), 70 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c > index 0fe505d..283747c 100644 > --- a/drivers/i2c/busses/i2c-sibyte.c > +++ b/drivers/i2c/busses/i2c-sibyte.c > @@ -2,6 +2,7 @@ > * Copyright (C) 2004 Steven J. Hill > * Copyright (C) 2001,2002,2003 Broadcom Corporation > * Copyright (C) 1995-2000 Simon G. Vogl > + * Copyright (C) 2008 Maciej W. Rozycki > * > * This program is free software; you can redistribute it and/or > * modify it under the terms of the GNU General Public License > @@ -18,104 +19,159 @@ > * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > */ > > +#include <linux/errno.h> > +#include <linux/interrupt.h> > #include <linux/kernel.h> > #include <linux/module.h> > #include <linux/init.h> > #include <linux/i2c.h> > +#include <linux/param.h> > +#include <linux/spinlock.h> > +#include <linux/types.h> > +#include <linux/wait.h> > #include <linux/io.h> > +#include <asm/sibyte/sb1250_int.h> > #include <asm/sibyte/sb1250_regs.h> > #include <asm/sibyte/sb1250_smbus.h> > > > struct i2c_algo_sibyte_data { > - void *data; /* private data */ > - int bus; /* which bus */ > - void *reg_base; /* CSR base */ > + wait_queue_head_t wait; /* IRQ queue */ > + void __iomem *csr; /* mapped CSR handle */ > + phys_t base; /* physical CSR base */ > + char *name; /* IRQ handler name */ > + spinlock_t lock; /* atomiser */ > + int irq; /* IRQ line */ > + int status; /* IRQ status */ > }; > > -/* ----- global defines ----------------------------------------------- */ > -#define SMB_CSR(a,r) ((long)(a->reg_base + r)) > > +static irqreturn_t i2c_sibyte_interrupt(int irq, void *dev_id) > +{ > + struct i2c_adapter *i2c_adap = dev_id; > + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr = adap->csr; > + u8 status; > + > + /* > + * Ugh, no way to detect the finish interrupt, > + * but if busy it is obviously not one. > + */ > + status = __raw_readq(csr + R_SMB_STATUS); > + if ((status & (M_SMB_ERROR | M_SMB_BUSY)) == M_SMB_BUSY) > + return IRQ_NONE; > > -static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, > - unsigned short flags, char read_write, > - u8 command, int size, union i2c_smbus_data * data) > + /* > + * Clear the error interrupt (write 1 to clear); > + * the finish interrupt was cleared by the read above. > + */ > + __raw_writeq(status, csr + R_SMB_STATUS); > + > + /* Post the status. */ > + spin_lock_irq(&adap->lock); > + adap->status = status & (M_SMB_ERROR_TYPE | M_SMB_ERROR | M_SMB_BUSY); > + wake_up(&adap->wait); > + spin_unlock_irq(&adap->lock); > + > + return IRQ_HANDLED; > +} > + > +static s32 i2c_sibyte_smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, > + unsigned short cflags, > + char read_write, u8 command, int size, > + union i2c_smbus_data *data) > { > struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr = adap->csr; > + unsigned long flags; > int data_bytes = 0; > int error; > > - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) > - ; > + spin_lock_irqsave(&adap->lock, flags); > + > + if (adap->status < 0) { > + error = -EIO; > + goto out_unlock; > + } If a previous operation timed out, subsequent operations will fail forever. Is this a good idea ? Maybe it is - just asking. > > switch (size) { > case I2C_SMBUS_QUICK: > - csr_out32((V_SMB_ADDR(addr) | > - (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | > - V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | > + (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | > + V_SMB_TT_QUICKCMD, > + csr + R_SMB_START); > break; > case I2C_SMBUS_BYTE: > if (read_write == I2C_SMBUS_READ) { > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE, > + csr + R_SMB_START); > data_bytes = 1; > } else { > - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE, > + csr + R_SMB_START); > } > break; > case I2C_SMBUS_BYTE_DATA: > - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); > + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); > if (read_write == I2C_SMBUS_READ) { > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE, > + csr + R_SMB_START); > data_bytes = 1; > } else { > - csr_out32(V_SMB_LB(data->byte), > - SMB_CSR(adap, R_SMB_DATA)); > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_LB(data->byte), csr + R_SMB_DATA); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, > + csr + R_SMB_START); > } > break; > case I2C_SMBUS_WORD_DATA: > - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); > + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); > if (read_write == I2C_SMBUS_READ) { > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE, > + csr + R_SMB_START); > data_bytes = 2; > } else { > - csr_out32(V_SMB_LB(data->word & 0xff), > - SMB_CSR(adap, R_SMB_DATA)); > - csr_out32(V_SMB_MB(data->word >> 8), > - SMB_CSR(adap, R_SMB_DATA)); > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_LB(data->word & 0xff), > + csr + R_SMB_DATA); > + __raw_writeq(V_SMB_MB(data->word >> 8), > + csr + R_SMB_DATA); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, > + csr + R_SMB_START); > } > break; > default: > - return -EOPNOTSUPP; > + error = -EOPNOTSUPP; > + goto out_unlock; > } > + mmiowb(); > + __raw_readq(csr + R_SMB_START); > + adap->status = -1; > + > + spin_unlock_irqrestore(&adap->lock, flags); > + > + wait_event_timeout(adap->wait, (adap->status >= 0), HZ); > > - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) > - ; > + spin_lock_irqsave(&adap->lock, flags); > > - error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); > - if (error & M_SMB_ERROR) { > - /* Clear error bit by writing a 1 */ > - csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); > - return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO; > + if (adap->status < 0 || (adap->status & (M_SMB_ERROR | M_SMB_BUSY))) { > + error = -EIO; > + goto out_unlock; > } The idea was to return -ENXIO if there was no ACK from a device (per Documentation/i2c/fault-codes). With your change, this distinction gets lost. I think you should retain the original semantics, ie return -ENXIO if status > 0 && ((status & (M_SMB_ERROR | M_SMB_ERROR_TYPE) == M_SMB_ERROR). > > if (data_bytes == 1) > - data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; > + data->byte = __raw_readq(csr + R_SMB_DATA) & 0xff; > if (data_bytes == 2) > - data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; > + data->word = __raw_readq(csr + R_SMB_DATA) & 0xffff; > > - return 0; > + error = 0; > + > +out_unlock: > + spin_unlock_irqrestore(&adap->lock, flags); > + > + return error; > } > > -static u32 bit_func(struct i2c_adapter *adap) > +static u32 i2c_sibyte_bit_func(struct i2c_adapter *adap) > { > return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | > I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); > @@ -125,8 +181,8 @@ static u32 bit_func(struct i2c_adapter *adap) > /* -----exported algorithm data: ------------------------------------- */ > > static const struct i2c_algorithm i2c_sibyte_algo = { > - .smbus_xfer = smbus_xfer, > - .functionality = bit_func, > + .smbus_xfer = i2c_sibyte_smbus_xfer, > + .functionality = i2c_sibyte_bit_func, > }; > > /* > @@ -135,37 +191,108 @@ static const struct i2c_algorithm i2c_sibyte_algo = { > static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) > { > struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr; > + int err; > > - /* Register new adapter to i2c module... */ > - i2c_adap->algo = &i2c_sibyte_algo; > + adap->status = 0; > + init_waitqueue_head(&adap->wait); > + spin_lock_init(&adap->lock); > + > + csr = ioremap(adap->base, R_SMB_PEC + SMB_REGISTER_SPACING); > + if (!csr) { > + err = -ENOMEM; > + goto out; > + } > + adap->csr = csr; > > /* Set the requested frequency. */ > - csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); > - csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); > + __raw_writeq(speed, csr + R_SMB_FREQ); > + > + /* Clear any pending error interrupt. */ > + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); > + /* Disable interrupts. */ > + __raw_writeq(0, csr + R_SMB_CONTROL); > + mmiowb(); > + __raw_readq(csr + R_SMB_CONTROL); > + > + err = request_irq(adap->irq, i2c_sibyte_interrupt, IRQF_SHARED, > + adap->name, i2c_adap); > + if (err < 0) > + goto out_unmap; > + > + /* Enable finish and error interrupts. */ > + __raw_writeq(M_SMB_FINISH_INTR | M_SMB_ERR_INTR, csr + R_SMB_CONTROL); > + > + /* Register new adapter to i2c module... */ > + err = i2c_add_numbered_adapter(i2c_adap); > + if (err < 0) > + goto out_unirq; > > - return i2c_add_numbered_adapter(i2c_adap); > + return 0; > + > +out_unirq: > + /* Disable interrupts. */ > + __raw_writeq(0, csr + R_SMB_CONTROL); > + mmiowb(); > + __raw_readq(csr + R_SMB_CONTROL); > + > + free_irq(adap->irq, i2c_adap); > + > + /* Clear any pending error interrupt. */ > + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); > +out_unmap: > + iounmap(csr); > +out: > + return err; > } > > +static void i2c_sibyte_remove_bus(struct i2c_adapter *i2c_adap) > +{ > + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr = adap->csr; > + > + i2c_del_adapter(i2c_adap); > + > + /* Disable interrupts. */ > + __raw_writeq(0, csr + R_SMB_CONTROL); > + mmiowb(); > + __raw_readq(csr + R_SMB_CONTROL); > + > + free_irq(adap->irq, i2c_adap); > + > + /* Clear any pending error interrupt. */ > + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); > + > + iounmap(csr); > +} > > -static struct i2c_algo_sibyte_data sibyte_board_data[2] = { > - { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, > - { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } > +static struct i2c_algo_sibyte_data i2c_sibyte_board_data[2] = { > + { > + .name = "sb1250-smbus-0", > + .base = A_SMB_0, > + .irq = K_INT_SMB_0, > + }, > + { > + .name = "sb1250-smbus-1", > + .base = A_SMB_1, > + .irq = K_INT_SMB_1, > + } > }; > > -static struct i2c_adapter sibyte_board_adapter[2] = { > +static struct i2c_adapter i2c_sibyte_board_adapter[2] = { > { > .owner = THIS_MODULE, > .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, > - .algo = NULL, > - .algo_data = &sibyte_board_data[0], > + .algo = &i2c_sibyte_algo, > + .algo_data = &i2c_sibyte_board_data[0], > .nr = 0, > .name = "SiByte SMBus 0", > }, > { > .owner = THIS_MODULE, > .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, > - .algo = NULL, > - .algo_data = &sibyte_board_data[1], > + .algo = &i2c_sibyte_algo, > + .algo_data = &i2c_sibyte_board_data[1], > .nr = 1, > .name = "SiByte SMBus 1", > }, > @@ -173,21 +300,32 @@ static struct i2c_adapter sibyte_board_adapter[2] = { > > static int __init i2c_sibyte_init(void) > { > + int err; > + > pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n"); > - if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0) > - return -ENODEV; > - if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], > - K_SMB_FREQ_400KHZ) < 0) { > - i2c_del_adapter(&sibyte_board_adapter[0]); > - return -ENODEV; > - } > + > + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[0], > + K_SMB_FREQ_100KHZ); > + if (err < 0) > + goto out; > + > + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[1], > + K_SMB_FREQ_400KHZ); > + if (err < 0) > + goto out_remove; > + > return 0; > + > +out_remove: > + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); > +out: > + return err; > } > > static void __exit i2c_sibyte_exit(void) > { > - i2c_del_adapter(&sibyte_board_adapter[0]); > - i2c_del_adapter(&sibyte_board_adapter[1]); > + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[1]); > + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); > } > > module_init(i2c_sibyte_init); > -- > 1.7.2.2 > > ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <1291617494-18430-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2010-12-06 14:59 ` Guenter Roeck @ 2010-12-06 17:30 ` Guenter Roeck [not found] ` <20101206173040.GA18372-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> 2010-12-06 17:56 ` Maciej W. Rozycki 2010-12-07 6:23 ` Guenter Roeck 2 siblings, 2 replies; 30+ messages in thread From: Guenter Roeck @ 2010-12-06 17:30 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle, Maciej W. Rozycki On Mon, Dec 06, 2010 at 01:38:14AM -0500, Matt Turner wrote: > From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > > This is a rewrite of large parts of the driver mainly so that it uses > SMBus interrupts to offload the CPU from busy-waiting on status inputs. > As a part of the overhaul of the init and exit calls, all accesses to the > hardware got converted to use accessory functions via an ioremap() cookie. > > Minimally rebased by Matt Turner. > > Tested-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> I applied the patch to my 1480 tree. Unfortunately, it doesn't work with my system. As far as I can see, the driver does not get any interrupts. My tree is 2.6.32, though. Do you know if I might be missing some other relevant patch ? Thanks, Guenter ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <20101206173040.GA18372-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <20101206173040.GA18372-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> @ 2010-12-06 17:40 ` Matt Turner [not found] ` <AANLkTikGgfBuj086eRvy4VzzyE2suJCL9z=SfmOiFiPx-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2010-12-06 17:40 UTC (permalink / raw) To: Guenter Roeck Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle, Maciej W. Rozycki On Mon, Dec 6, 2010 at 5:30 PM, Guenter Roeck <guenter.roeck-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> wrote: > On Mon, Dec 06, 2010 at 01:38:14AM -0500, Matt Turner wrote: >> From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> >> >> This is a rewrite of large parts of the driver mainly so that it uses >> SMBus interrupts to offload the CPU from busy-waiting on status inputs. >> As a part of the overhaul of the init and exit calls, all accesses to the >> hardware got converted to use accessory functions via an ioremap() cookie. >> >> Minimally rebased by Matt Turner. >> >> Tested-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> >> Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > > > I applied the patch to my 1480 tree. Unfortunately, it doesn't work with my system. > As far as I can see, the driver does not get any interrupts. > > My tree is 2.6.32, though. Do you know if I might be missing some other relevant patch ? > > Thanks, > Guenter I think this patch depends on http://www.linux-mips.org/archives/linux-mips/2010-12/msg00030.html Thanks for testing and the suggestions! :) Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <AANLkTikGgfBuj086eRvy4VzzyE2suJCL9z=SfmOiFiPx-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <AANLkTikGgfBuj086eRvy4VzzyE2suJCL9z=SfmOiFiPx-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2010-12-06 18:02 ` Guenter Roeck 2010-12-06 18:04 ` Matt Turner 0 siblings, 1 reply; 30+ messages in thread From: Guenter Roeck @ 2010-12-06 18:02 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle, Maciej W. Rozycki On Mon, Dec 06, 2010 at 12:40:15PM -0500, Matt Turner wrote: > On Mon, Dec 6, 2010 at 5:30 PM, Guenter Roeck > <guenter.roeck-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> wrote: > > On Mon, Dec 06, 2010 at 01:38:14AM -0500, Matt Turner wrote: > >> From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > >> > >> This is a rewrite of large parts of the driver mainly so that it uses > >> SMBus interrupts to offload the CPU from busy-waiting on status inputs. > >> As a part of the overhaul of the init and exit calls, all accesses to the > >> hardware got converted to use accessory functions via an ioremap() cookie. > >> > >> Minimally rebased by Matt Turner. > >> > >> Tested-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > >> Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > > > > > > I applied the patch to my 1480 tree. Unfortunately, it doesn't work with my system. > > As far as I can see, the driver does not get any interrupts. > > > > My tree is 2.6.32, though. Do you know if I might be missing some other relevant patch ? > > > > Thanks, > > Guenter > > I think this patch depends on > http://www.linux-mips.org/archives/linux-mips/2010-12/msg00030.html > I did apply the second patch as well, since you had mentioned it in your patch. That did not help, though. Frankly, I don't see the dependency in the first place - the other patch only affects drivers/rtc/rtc-m41t80.c, and I would hope that SMBus support does not depend on an rtc driver. Am I missing something ? Thanks, Guenter ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts 2010-12-06 18:02 ` Guenter Roeck @ 2010-12-06 18:04 ` Matt Turner 0 siblings, 0 replies; 30+ messages in thread From: Matt Turner @ 2010-12-06 18:04 UTC (permalink / raw) To: Guenter Roeck Cc: Jean Delvare, linux-i2c@vger.kernel.org, linux-mips@linux-mips.org, Ralf Baechle, Maciej W. Rozycki On Mon, Dec 6, 2010 at 6:02 PM, Guenter Roeck <guenter.roeck@ericsson.com> wrote: > On Mon, Dec 06, 2010 at 12:40:15PM -0500, Matt Turner wrote: >> On Mon, Dec 6, 2010 at 5:30 PM, Guenter Roeck >> <guenter.roeck@ericsson.com> wrote: >> > On Mon, Dec 06, 2010 at 01:38:14AM -0500, Matt Turner wrote: >> >> From: Maciej W. Rozycki <macro@linux-mips.org> >> >> >> >> This is a rewrite of large parts of the driver mainly so that it uses >> >> SMBus interrupts to offload the CPU from busy-waiting on status inputs. >> >> As a part of the overhaul of the init and exit calls, all accesses to the >> >> hardware got converted to use accessory functions via an ioremap() cookie. >> >> >> >> Minimally rebased by Matt Turner. >> >> >> >> Tested-by: Matt Turner <mattst88@gmail.com> >> >> Signed-off-by: Matt Turner <mattst88@gmail.com> >> > >> > >> > I applied the patch to my 1480 tree. Unfortunately, it doesn't work with my system. >> > As far as I can see, the driver does not get any interrupts. >> > >> > My tree is 2.6.32, though. Do you know if I might be missing some other relevant patch ? >> > >> > Thanks, >> > Guenter >> >> I think this patch depends on >> http://www.linux-mips.org/archives/linux-mips/2010-12/msg00030.html >> > I did apply the second patch as well, since you had mentioned it in your patch. > That did not help, though. Frankly, I don't see the dependency in the first place - the other > patch only affects drivers/rtc/rtc-m41t80.c, and I would hope that SMBus support does not depend > on an rtc driver. Am I missing something ? > > Thanks, > Guenter Indeed that does not make much sense. I really don't know. Perhaps Maciej can shed some light on this? It certainly might be the case that these patches haven't ever been tested on a BCM91480 before. Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts 2010-12-06 17:30 ` Guenter Roeck [not found] ` <20101206173040.GA18372-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> @ 2010-12-06 17:56 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1012061739200.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 1 sibling, 1 reply; 30+ messages in thread From: Maciej W. Rozycki @ 2010-12-06 17:56 UTC (permalink / raw) To: Guenter Roeck Cc: Matt Turner, Jean Delvare, linux-i2c@vger.kernel.org, linux-mips@linux-mips.org, Ralf Baechle On Mon, 6 Dec 2010, Guenter Roeck wrote: > > From: Maciej W. Rozycki <macro@linux-mips.org> > > > > This is a rewrite of large parts of the driver mainly so that it uses > > SMBus interrupts to offload the CPU from busy-waiting on status inputs. > > As a part of the overhaul of the init and exit calls, all accesses to the > > hardware got converted to use accessory functions via an ioremap() cookie. > > > > Minimally rebased by Matt Turner. > > > > Tested-by: Matt Turner <mattst88@gmail.com> > > Signed-off-by: Matt Turner <mattst88@gmail.com> > > I applied the patch to my 1480 tree. Unfortunately, it doesn't work with > my system. As far as I can see, the driver does not get any interrupts. > > My tree is 2.6.32, though. Do you know if I might be missing some other > relevant patch ? As the original author I apologise for the lack of response about these changes -- I've had a really, really hectic time recently and will continue to suffer from that for several weeks yet at the very least. As to the patches -- these I submitted originally back in 2008 as a series. There may have been more than one series actually, but I can't recall the details offhand. There were some discussions and concerns about some of the patches which in the end I did not fully address owing to various disruptions and the lack of time, which is why they did not go in. I do remember some bits about interrupt handling as the original implementation of the I2C host interface used polling only and I saw it as a gross inefficiency. Obviously with all the bits in place they used to work at least for me. Matt, thanks for keeping your eye on these bits and reviving them; I've meant to do so for a long time now, but never came to it. Please note however, as I'm the original author, my original Signed-off-by markups continue to apply and you should be quoting them with the submissions. You should only add your own Signed-off-by annotation if you made any changes and it would make sense to state what these changes were. I'll do my best to provide some aid with these bits, but won't be able to do anything but plain code review up till January at the very least, and then maybe not even that. My SWARM board has been stuck with 2.6.27-ish for a long while now. Sorry. Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <alpine.LFD.2.00.1012061739200.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <alpine.LFD.2.00.1012061739200.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> @ 2010-12-06 18:02 ` Matt Turner [not found] ` <AANLkTikWRsgHao_eb4W47b=E4vm6z=hi36JE_VBtD6Rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2010-12-06 18:02 UTC (permalink / raw) To: Maciej W. Rozycki Cc: Guenter Roeck, Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle On Mon, Dec 6, 2010 at 5:56 PM, Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> wrote: > Matt, thanks for keeping your eye on these bits and reviving them; I've > meant to do so for a long time now, but never came to it. Please note > however, as I'm the original author, my original Signed-off-by markups > continue to apply and you should be quoting them with the submissions. > You should only add your own Signed-off-by annotation if you made any > changes and it would make sense to state what these changes were. Sure thing. Will fix. For patches 2 and 3 of the other series, I don't think I was ever 100% sure that you were the author, since they were living on OpenWRT.org and I couldn't find them in any mailing list archives. Can you confirm that these 4 patches are all yours? Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <AANLkTikWRsgHao_eb4W47b=E4vm6z=hi36JE_VBtD6Rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <AANLkTikWRsgHao_eb4W47b=E4vm6z=hi36JE_VBtD6Rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2010-12-07 2:26 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1012070148050.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Maciej W. Rozycki @ 2010-12-07 2:26 UTC (permalink / raw) To: Matt Turner Cc: Guenter Roeck, Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle On Mon, 6 Dec 2010, Matt Turner wrote: > > Matt, thanks for keeping your eye on these bits and reviving them; I've > > meant to do so for a long time now, but never came to it. Please note > > however, as I'm the original author, my original Signed-off-by markups > > continue to apply and you should be quoting them with the submissions. > > You should only add your own Signed-off-by annotation if you made any > > changes and it would make sense to state what these changes were. > > Sure thing. Will fix. For patches 2 and 3 of the other series, I don't > think I was ever 100% sure that you were the author, since they were > living on OpenWRT.org and I couldn't find them in any mailing list > archives. Can you confirm that these 4 patches are all yours? All the relevant submissions should be present here: http://www.linux-mips.org/archives/linux-mips/2008-05/threads.html Specifically: http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=Pine.LNX.4.55.0805180447210.10067%40cliff.in.clinika.pl (5th of a series of 6), and: http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=Pine.LNX.4.55.0805070054440.16173%40cliff.in.clinika.pl (3rd of a series of 4), and: http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=Pine.LNX.4.55.0805130353250.535%40cliff.in.clinika.pl (individual submission). The "clean up SWARM RTC setup" change seems to be modified (lacking e.g. a proper read_persistent_clock() implementation) compared to my proposal (second above) and most likely came from someone else and the lm90 change definitely comes from someone else. Note that for IRQ support you may have to investigate dependencies in the other two series as the patch (third above) was intended to apply on top of the two series (select the date sort for easier identification of the series). I'd have to dig into that code for further details and I cannot afford the time right now, sorry. Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <alpine.LFD.2.00.1012070148050.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <alpine.LFD.2.00.1012070148050.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> @ 2010-12-07 5:14 ` Guenter Roeck [not found] ` <20101207051438.GA20144-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Guenter Roeck @ 2010-12-07 5:14 UTC (permalink / raw) To: Maciej W. Rozycki Cc: Matt Turner, Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle On Mon, Dec 06, 2010 at 09:26:54PM -0500, Maciej W. Rozycki wrote: [ ... ] > > Note that for IRQ support you may have to investigate dependencies in the > other two series as the patch (third above) was intended to apply on top > of the two series (select the date sort for easier identification of the > series). I'd have to dig into that code for further details and I cannot > afford the time right now, sorry. > A quick look through sb1250 vs. sb1480 code shows that the 1480 uses different interrupt numbers. The patch assigns the sb1250 interrupt numbers, so unless I am missing something the code as written can not work for sb1480. Thanks, Guenter ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <20101207051438.GA20144-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <20101207051438.GA20144-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> @ 2010-12-07 14:30 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1012070740130.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Maciej W. Rozycki @ 2010-12-07 14:30 UTC (permalink / raw) To: Guenter Roeck Cc: Matt Turner, Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle On Mon, 6 Dec 2010, Guenter Roeck wrote: > A quick look through sb1250 vs. sb1480 code shows that the 1480 uses different > interrupt numbers. The patch assigns the sb1250 interrupt numbers, so unless > I am missing something the code as written can not work for sb1480. That well could be -- I never had access to a BigSur board. The board-specific interrupt numbers should either be available from the board manual (I haven't checked if one has been released; I certainly have one for my SWARM) or quoted somewhere in our tree. Otherwise figuring them out by trial and error should be a trivial exercise for someone with actual hardware at hand. Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <alpine.LFD.2.00.1012070740130.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <alpine.LFD.2.00.1012070740130.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> @ 2010-12-07 14:41 ` Guenter Roeck 0 siblings, 0 replies; 30+ messages in thread From: Guenter Roeck @ 2010-12-07 14:41 UTC (permalink / raw) To: Maciej W. Rozycki Cc: Matt Turner, Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle On Tue, Dec 07, 2010 at 09:30:27AM -0500, Maciej W. Rozycki wrote: > On Mon, 6 Dec 2010, Guenter Roeck wrote: > > > A quick look through sb1250 vs. sb1480 code shows that the 1480 uses different > > interrupt numbers. The patch assigns the sb1250 interrupt numbers, so unless > > I am missing something the code as written can not work for sb1480. > > That well could be -- I never had access to a BigSur board. The > board-specific interrupt numbers should either be available from the board > manual (I haven't checked if one has been released; I certainly have one > for my SWARM) or quoted somewhere in our tree. Otherwise figuring them > out by trial and error should be a trivial exercise for someone with > actual hardware at hand. > I already sent a reply to the original patch - I confirmed that the interrupts are different. Those are SOC interrupts, so they are CPU specific, not board specific. Code started working after I replaced the sb1250 interrupts with bcm1480 interrupts. Guenter ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <1291617494-18430-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2010-12-06 14:59 ` Guenter Roeck 2010-12-06 17:30 ` Guenter Roeck @ 2010-12-07 6:23 ` Guenter Roeck 2 siblings, 0 replies; 30+ messages in thread From: Guenter Roeck @ 2010-12-07 6:23 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle, Maciej W. Rozycki On Mon, Dec 06, 2010 at 01:38:14AM -0500, Matt Turner wrote: > From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > > This is a rewrite of large parts of the driver mainly so that it uses > SMBus interrupts to offload the CPU from busy-waiting on status inputs. > As a part of the overhaul of the init and exit calls, all accesses to the > hardware got converted to use accessory functions via an ioremap() cookie. > > Minimally rebased by Matt Turner. > > Tested-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> [ .. ] > > -static struct i2c_algo_sibyte_data sibyte_board_data[2] = { > - { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, > - { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } > +static struct i2c_algo_sibyte_data i2c_sibyte_board_data[2] = { > + { > + .name = "sb1250-smbus-0", > + .base = A_SMB_0, > + .irq = K_INT_SMB_0, > + }, > + { > + .name = "sb1250-smbus-1", > + .base = A_SMB_1, > + .irq = K_INT_SMB_1, Found my problem. The .irq settings don't work for BCM1480. It needs K_BCM1480_INT_SMB_0 and K_BCM1480_INT_SMB_1 from asm/sibyte/bcm1480_int.h. For a clean fix, i2c_sibyte_board_data[] should probably be defined in a platform file, not in the i2c bus driver. Guenter ^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH] I2C: SiByte: Convert the driver to make use of interrupts @ 2011-08-18 23:43 Matt Turner [not found] ` <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2011-08-18 23:43 UTC (permalink / raw) To: Jean Delvare Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki, Matt Turner From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> This is a rewrite of large parts of the driver mainly so that it uses SMBus interrupts to offload the CPU from busy-waiting on status inputs. As a part of the overhaul of the init and exit calls, all accesses to the hardware got converted to use accessory functions via an ioremap() cookie. [mattst88] Added BCM1480 interrupts and rebased minimally. Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Signed-off-by: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> --- This is the second version of this patch that I've sent. This version fixes the problem with the ENXIO return. drivers/i2c/busses/i2c-sibyte.c | 296 +++++++++++++++++++++++++++++--------- 1 files changed, 226 insertions(+), 70 deletions(-) diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 0fe505d..d2f1cf1 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -2,6 +2,7 @@ * Copyright (C) 2004 Steven J. Hill * Copyright (C) 2001,2002,2003 Broadcom Corporation * Copyright (C) 1995-2000 Simon G. Vogl + * Copyright (C) 2008 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,104 +19,164 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/errno.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/param.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/wait.h> #include <linux/io.h> +#include <asm/sibyte/sb1250_int.h> #include <asm/sibyte/sb1250_regs.h> #include <asm/sibyte/sb1250_smbus.h> +#include <asm/sibyte/bcm1480_int.h> struct i2c_algo_sibyte_data { - void *data; /* private data */ - int bus; /* which bus */ - void *reg_base; /* CSR base */ + wait_queue_head_t wait; /* IRQ queue */ + void __iomem *csr; /* mapped CSR handle */ + phys_t base; /* physical CSR base */ + char *name; /* IRQ handler name */ + spinlock_t lock; /* atomiser */ + int irq; /* IRQ line */ + int status; /* IRQ status */ }; -/* ----- global defines ----------------------------------------------- */ -#define SMB_CSR(a,r) ((long)(a->reg_base + r)) +static irqreturn_t i2c_sibyte_interrupt(int irq, void *dev_id) +{ + struct i2c_adapter *i2c_adap = dev_id; + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + u8 status; + + /* + * Ugh, no way to detect the finish interrupt, + * but if busy it is obviously not one. + */ + status = __raw_readq(csr + R_SMB_STATUS); + if ((status & (M_SMB_ERROR | M_SMB_BUSY)) == M_SMB_BUSY) + return IRQ_NONE; + + /* + * Clear the error interrupt (write 1 to clear); + * the finish interrupt was cleared by the read above. + */ + __raw_writeq(status, csr + R_SMB_STATUS); + + /* Post the status. */ + spin_lock(&adap->lock); + adap->status = status & (M_SMB_ERROR_TYPE | M_SMB_ERROR | M_SMB_BUSY); + wake_up(&adap->wait); + spin_unlock(&adap->lock); + + return IRQ_HANDLED; +} -static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) +static s32 i2c_sibyte_smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, + unsigned short cflags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) { struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + unsigned long flags; int data_bytes = 0; int error; - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; + spin_lock_irqsave(&adap->lock, flags); + + if (adap->status < 0) { + error = -EIO; + goto out_unlock; + } switch (size) { case I2C_SMBUS_QUICK: - csr_out32((V_SMB_ADDR(addr) | - (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | - V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | + (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | + V_SMB_TT_QUICKCMD, + csr + R_SMB_START); break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE, + csr + R_SMB_START); data_bytes = 1; } else { - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE, + csr + R_SMB_START); } break; case I2C_SMBUS_BYTE_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE, + csr + R_SMB_START); data_bytes = 1; } else { - csr_out32(V_SMB_LB(data->byte), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_LB(data->byte), csr + R_SMB_DATA); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, + csr + R_SMB_START); } break; case I2C_SMBUS_WORD_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE, + csr + R_SMB_START); data_bytes = 2; } else { - csr_out32(V_SMB_LB(data->word & 0xff), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32(V_SMB_MB(data->word >> 8), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_LB(data->word & 0xff), + csr + R_SMB_DATA); + __raw_writeq(V_SMB_MB(data->word >> 8), + csr + R_SMB_DATA); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, + csr + R_SMB_START); } break; default: - return -EOPNOTSUPP; + error = -EOPNOTSUPP; + goto out_unlock; } + mmiowb(); + __raw_readq(csr + R_SMB_START); + adap->status = -1; + + spin_unlock_irqrestore(&adap->lock, flags); - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; + wait_event_timeout(adap->wait, (adap->status >= 0), HZ); - error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); - if (error & M_SMB_ERROR) { - /* Clear error bit by writing a 1 */ - csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); - return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO; + spin_lock_irqsave(&adap->lock, flags); + + if (adap->status > 0 && ((adap->status & (M_SMB_ERROR | M_SMB_ERROR_TYPE)) == M_SMB_ERROR)) { + error = -ENXIO; + goto out_unlock; + } + if (adap->status < 0 || (adap->status & (M_SMB_ERROR | M_SMB_BUSY))) { + error = -EIO; + goto out_unlock; } if (data_bytes == 1) - data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; + data->byte = __raw_readq(csr + R_SMB_DATA) & 0xff; if (data_bytes == 2) - data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; + data->word = __raw_readq(csr + R_SMB_DATA) & 0xffff; - return 0; + error = 0; + +out_unlock: + spin_unlock_irqrestore(&adap->lock, flags); + + return error; } -static u32 bit_func(struct i2c_adapter *adap) +static u32 i2c_sibyte_bit_func(struct i2c_adapter *adap) { return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); @@ -125,8 +186,8 @@ static u32 bit_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static const struct i2c_algorithm i2c_sibyte_algo = { - .smbus_xfer = smbus_xfer, - .functionality = bit_func, + .smbus_xfer = i2c_sibyte_smbus_xfer, + .functionality = i2c_sibyte_bit_func, }; /* @@ -135,37 +196,121 @@ static const struct i2c_algorithm i2c_sibyte_algo = { static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) { struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr; + int err; - /* Register new adapter to i2c module... */ - i2c_adap->algo = &i2c_sibyte_algo; + adap->status = 0; + init_waitqueue_head(&adap->wait); + spin_lock_init(&adap->lock); + + csr = ioremap(adap->base, R_SMB_PEC + SMB_REGISTER_SPACING); + if (!csr) { + err = -ENOMEM; + goto out; + } + adap->csr = csr; /* Set the requested frequency. */ - csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); - csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); + __raw_writeq(speed, csr + R_SMB_FREQ); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + err = request_irq(adap->irq, i2c_sibyte_interrupt, IRQF_SHARED, + adap->name, i2c_adap); + if (err < 0) + goto out_unmap; + + /* Enable finish and error interrupts. */ + __raw_writeq(M_SMB_FINISH_INTR | M_SMB_ERR_INTR, csr + R_SMB_CONTROL); + + /* Register new adapter to i2c module... */ + err = i2c_add_numbered_adapter(i2c_adap); + if (err < 0) + goto out_unirq; + + return 0; - return i2c_add_numbered_adapter(i2c_adap); +out_unirq: + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + free_irq(adap->irq, i2c_adap); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); +out_unmap: + iounmap(csr); +out: + return err; } +static void i2c_sibyte_remove_bus(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + + i2c_del_adapter(i2c_adap); + + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); -static struct i2c_algo_sibyte_data sibyte_board_data[2] = { - { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, - { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } + free_irq(adap->irq, i2c_adap); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); + + iounmap(csr); +} + +static struct i2c_algo_sibyte_data i2c_sibyte_board_data[2] = { +#ifdef CONFIG_SIBYTE_SB1250 + { + .name = "sb1250-smbus-0", + .base = A_SMB_0, + .irq = K_INT_SMB_0, + }, + { + .name = "sb1250-smbus-1", + .base = A_SMB_1, + .irq = K_INT_SMB_1, + } +#else + { + .name = "bcm1480-smbus-0", + .base = A_SMB_0, + .irq = K_BCM1480_INT_SMB_0, + }, + { + .name = "bcm1480-smbus-1", + .base = A_SMB_1, + .irq = K_BCM1480_INT_SMB_1, + } +#endif }; -static struct i2c_adapter sibyte_board_adapter[2] = { +static struct i2c_adapter i2c_sibyte_board_adapter[2] = { { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = NULL, - .algo_data = &sibyte_board_data[0], + .algo = &i2c_sibyte_algo, + .algo_data = &i2c_sibyte_board_data[0], .nr = 0, .name = "SiByte SMBus 0", }, { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = NULL, - .algo_data = &sibyte_board_data[1], + .algo = &i2c_sibyte_algo, + .algo_data = &i2c_sibyte_board_data[1], .nr = 1, .name = "SiByte SMBus 1", }, @@ -173,21 +318,32 @@ static struct i2c_adapter sibyte_board_adapter[2] = { static int __init i2c_sibyte_init(void) { + int err; + pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n"); - if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0) - return -ENODEV; - if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], - K_SMB_FREQ_400KHZ) < 0) { - i2c_del_adapter(&sibyte_board_adapter[0]); - return -ENODEV; - } + + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[0], + K_SMB_FREQ_100KHZ); + if (err < 0) + goto out; + + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[1], + K_SMB_FREQ_400KHZ); + if (err < 0) + goto out_remove; + return 0; + +out_remove: + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); +out: + return err; } static void __exit i2c_sibyte_exit(void) { - i2c_del_adapter(&sibyte_board_adapter[0]); - i2c_del_adapter(&sibyte_board_adapter[1]); + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[1]); + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); } module_init(i2c_sibyte_init); -- 1.7.3.4 ^ permalink raw reply related [flat|nested] 30+ messages in thread
[parent not found: <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2011-08-22 20:02 ` Guenter Roeck 2011-08-24 15:36 ` Matt Turner 2011-09-03 8:30 ` Jean Delvare 2 siblings, 0 replies; 30+ messages in thread From: Guenter Roeck @ 2011-08-22 20:02 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org, Ralf Baechle, Maciej W. Rozycki On Thu, 2011-08-18 at 19:43 -0400, Matt Turner wrote: > From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > > This is a rewrite of large parts of the driver mainly so that it uses > SMBus interrupts to offload the CPU from busy-waiting on status inputs. > As a part of the overhaul of the init and exit calls, all accesses to the > hardware got converted to use accessory functions via an ioremap() cookie. > > [mattst88] Added BCM1480 interrupts and rebased minimally. > > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> Patch works fine on our target, and shows significant speed improvements for i2c accesses. Linux version 3.0.3-428-g17c1f3f (groeck@rbos-pc-13) (gcc version 4.4.1 (Debian 4.4.1-1) ) #2 SMP Mon Aug 22 12:56:41 PDT 2011 bootconsole [early0] enabled CPU revision is: 01041100 (SiByte SB1A) FPU revision is: 000f0103 Checking for the multiply/shift bug... no. Checking for the daddiu bug... no. Broadcom SiByte BCM1480 B1 (pass2) @ 900 MHz (SB-1A rev 0) Tested-by: Guenter Roeck <guenter.roeck-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> Guenter ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2011-08-22 20:02 ` Guenter Roeck @ 2011-08-24 15:36 ` Matt Turner [not found] ` <CAEdQ38E6qqVAKC1MkAWto5yeU9N2uoyGY1Y5431kNUNL_yc8EA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2011-09-03 8:30 ` Jean Delvare 2 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2011-08-24 15:36 UTC (permalink / raw) To: Jean Delvare Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki, Matt Turner On Thu, Aug 18, 2011 at 7:43 PM, Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> Jean, Do you want to take this patch, or should Ralf through his tree? Thanks, Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <CAEdQ38E6qqVAKC1MkAWto5yeU9N2uoyGY1Y5431kNUNL_yc8EA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <CAEdQ38E6qqVAKC1MkAWto5yeU9N2uoyGY1Y5431kNUNL_yc8EA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2011-09-02 13:21 ` Jean Delvare 2011-09-02 13:35 ` Maciej W. Rozycki 0 siblings, 1 reply; 30+ messages in thread From: Jean Delvare @ 2011-09-02 13:21 UTC (permalink / raw) To: Matt Turner Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki On Wed, 24 Aug 2011 11:36:48 -0400, Matt Turner wrote: > On Thu, Aug 18, 2011 at 7:43 PM, Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > > Signed-off-by: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > > Do you want to take this patch, or should Ralf through his tree? My tree is fine, unless Ralf has a specific reason to pick it. Just give me a couple hours to review the patch. -- Jean Delvare ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts 2011-09-02 13:21 ` Jean Delvare @ 2011-09-02 13:35 ` Maciej W. Rozycki 0 siblings, 0 replies; 30+ messages in thread From: Maciej W. Rozycki @ 2011-09-02 13:35 UTC (permalink / raw) To: Jean Delvare Cc: Matt Turner, linux-i2c, linux-mips, Ralf Baechle, Guenter Roeck On Fri, 2 Sep 2011, Jean Delvare wrote: > > > Signed-off-by: Matt Turner <mattst88@gmail.com> > > > Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> > > > > Do you want to take this patch, or should Ralf through his tree? > > My tree is fine, unless Ralf has a specific reason to pick it. Just > give me a couple hours to review the patch. As a side note I do really need to get back to this series and see if there's anything else that needs reviving. Hopefully within the next couple of weeks. Thanks, Matt, for taking care of this patch. I reckon I've got some other old SWARM stuff that needs digging up too. Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2011-08-22 20:02 ` Guenter Roeck 2011-08-24 15:36 ` Matt Turner @ 2011-09-03 8:30 ` Jean Delvare [not found] ` <20110903103036.161616a5-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 2 siblings, 1 reply; 30+ messages in thread From: Jean Delvare @ 2011-09-03 8:30 UTC (permalink / raw) To: Matt Turner Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki Hi Matt, On Thu, 18 Aug 2011 19:43:11 -0400, Matt Turner wrote: > From: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > > This is a rewrite of large parts of the driver mainly so that it uses > SMBus interrupts to offload the CPU from busy-waiting on status inputs. > As a part of the overhaul of the init and exit calls, all accesses to the > hardware got converted to use accessory functions via an ioremap() cookie. This could have been split into incremental patches, to make review easier. > [mattst88] Added BCM1480 interrupts and rebased minimally. Ditto. checkpatch complains about this, please fix: WARNING: line over 80 characters #257: FILE: drivers/i2c/busses/i2c-sibyte.c:157: + if (adap->status > 0 && ((adap->status & (M_SMB_ERROR | M_SMB_ERROR_TYPE)) == M_SMB_ERROR)) { Very nice patch overall, I only have minor comments, see below inline. > > Signed-off-by: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Maciej W. Rozycki <macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org> > --- > This is the second version of this patch that I've sent. This version > fixes the problem with the ENXIO return. > > drivers/i2c/busses/i2c-sibyte.c | 296 +++++++++++++++++++++++++++++--------- > 1 files changed, 226 insertions(+), 70 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c > index 0fe505d..d2f1cf1 100644 > --- a/drivers/i2c/busses/i2c-sibyte.c > +++ b/drivers/i2c/busses/i2c-sibyte.c > @@ -2,6 +2,7 @@ > * Copyright (C) 2004 Steven J. Hill > * Copyright (C) 2001,2002,2003 Broadcom Corporation > * Copyright (C) 1995-2000 Simon G. Vogl > + * Copyright (C) 2008 Maciej W. Rozycki Wow, looks like this patch has been sleeping for quite some time... > * > * This program is free software; you can redistribute it and/or > * modify it under the terms of the GNU General Public License > @@ -18,104 +19,164 @@ > * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > */ > > +#include <linux/errno.h> > +#include <linux/interrupt.h> > #include <linux/kernel.h> > #include <linux/module.h> > #include <linux/init.h> > #include <linux/i2c.h> > +#include <linux/param.h> > +#include <linux/spinlock.h> > +#include <linux/types.h> > +#include <linux/wait.h> > #include <linux/io.h> > +#include <asm/sibyte/sb1250_int.h> > #include <asm/sibyte/sb1250_regs.h> > #include <asm/sibyte/sb1250_smbus.h> > +#include <asm/sibyte/bcm1480_int.h> > > > struct i2c_algo_sibyte_data { > - void *data; /* private data */ > - int bus; /* which bus */ > - void *reg_base; /* CSR base */ > + wait_queue_head_t wait; /* IRQ queue */ > + void __iomem *csr; /* mapped CSR handle */ > + phys_t base; /* physical CSR base */ > + char *name; /* IRQ handler name */ Should be a const pointer. Also, if the name is only for the IRQ, then irq_name would be a better name. > + spinlock_t lock; /* atomiser */ A more useful comment would explain what exactly is being protected by the lock. > + int irq; /* IRQ line */ > + int status; /* IRQ status */ You could document than -1 means error. > }; > > -/* ----- global defines ----------------------------------------------- */ > -#define SMB_CSR(a,r) ((long)(a->reg_base + r)) > > +static irqreturn_t i2c_sibyte_interrupt(int irq, void *dev_id) > +{ > + struct i2c_adapter *i2c_adap = dev_id; > + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr = adap->csr; > + u8 status; > + > + /* > + * Ugh, no way to detect the finish interrupt, > + * but if busy it is obviously not one. > + */ > + status = __raw_readq(csr + R_SMB_STATUS); > + if ((status & (M_SMB_ERROR | M_SMB_BUSY)) == M_SMB_BUSY) > + return IRQ_NONE; > + > + /* > + * Clear the error interrupt (write 1 to clear); > + * the finish interrupt was cleared by the read above. > + */ > + __raw_writeq(status, csr + R_SMB_STATUS); > + > + /* Post the status. */ > + spin_lock(&adap->lock); > + adap->status = status & (M_SMB_ERROR_TYPE | M_SMB_ERROR | M_SMB_BUSY); > + wake_up(&adap->wait); > + spin_unlock(&adap->lock); > + > + return IRQ_HANDLED; > +} > > -static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, > - unsigned short flags, char read_write, > - u8 command, int size, union i2c_smbus_data * data) > +static s32 i2c_sibyte_smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, > + unsigned short cflags, > + char read_write, u8 command, int size, > + union i2c_smbus_data *data) > { > struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr = adap->csr; > + unsigned long flags; > int data_bytes = 0; > int error; > > - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) > - ; > + spin_lock_irqsave(&adap->lock, flags); > + > + if (adap->status < 0) { > + error = -EIO; > + goto out_unlock; > + } Well, this can only happen if the previous transaction ended up with a failure, right? This means that a single error will break the SMBus forever. Is there no way to reset the controller to a sane state if this happens? > > switch (size) { > case I2C_SMBUS_QUICK: > - csr_out32((V_SMB_ADDR(addr) | > - (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | > - V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | > + (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | > + V_SMB_TT_QUICKCMD, > + csr + R_SMB_START); > break; > case I2C_SMBUS_BYTE: > if (read_write == I2C_SMBUS_READ) { > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE, > + csr + R_SMB_START); > data_bytes = 1; > } else { > - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE, > + csr + R_SMB_START); > } > break; > case I2C_SMBUS_BYTE_DATA: > - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); > + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); > if (read_write == I2C_SMBUS_READ) { > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE, > + csr + R_SMB_START); > data_bytes = 1; > } else { > - csr_out32(V_SMB_LB(data->byte), > - SMB_CSR(adap, R_SMB_DATA)); > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_LB(data->byte), csr + R_SMB_DATA); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, > + csr + R_SMB_START); > } > break; > case I2C_SMBUS_WORD_DATA: > - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); > + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); > if (read_write == I2C_SMBUS_READ) { > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE, > + csr + R_SMB_START); > data_bytes = 2; > } else { > - csr_out32(V_SMB_LB(data->word & 0xff), > - SMB_CSR(adap, R_SMB_DATA)); > - csr_out32(V_SMB_MB(data->word >> 8), > - SMB_CSR(adap, R_SMB_DATA)); > - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), > - SMB_CSR(adap, R_SMB_START)); > + __raw_writeq(V_SMB_LB(data->word & 0xff), > + csr + R_SMB_DATA); > + __raw_writeq(V_SMB_MB(data->word >> 8), > + csr + R_SMB_DATA); > + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, > + csr + R_SMB_START); > } > break; > default: > - return -EOPNOTSUPP; > + error = -EOPNOTSUPP; > + goto out_unlock; > } > + mmiowb(); > + __raw_readq(csr + R_SMB_START); > + adap->status = -1; > + > + spin_unlock_irqrestore(&adap->lock, flags); > > - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) > - ; > + wait_event_timeout(adap->wait, (adap->status >= 0), HZ); 1 second is a rather long timeout. The driver only supports small transactions, so even if a slave slows down the clock, I can hardly imagine a transaction lasting more that, say, 10 ms. So I think you can safely lower the timeout to HZ / 5 or even HZ / 10. Also, shouldn't you check the return value? This would let you return the right error code (-ETIMEDOUT according to Documentation/i2c/fault-codes) and you would no longer have to check for adap->status sign in the rest of the function. > > - error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); > - if (error & M_SMB_ERROR) { > - /* Clear error bit by writing a 1 */ > - csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); > - return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO; > + spin_lock_irqsave(&adap->lock, flags); > + > + if (adap->status > 0 && ((adap->status & (M_SMB_ERROR | M_SMB_ERROR_TYPE)) == M_SMB_ERROR)) { > + error = -ENXIO; > + goto out_unlock; > + } > + if (adap->status < 0 || (adap->status & (M_SMB_ERROR | M_SMB_BUSY))) { > + error = -EIO; > + goto out_unlock; > } > > if (data_bytes == 1) > - data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; > + data->byte = __raw_readq(csr + R_SMB_DATA) & 0xff; > if (data_bytes == 2) > - data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; > + data->word = __raw_readq(csr + R_SMB_DATA) & 0xffff; > > - return 0; > + error = 0; > + > +out_unlock: > + spin_unlock_irqrestore(&adap->lock, flags); > + > + return error; > } > > -static u32 bit_func(struct i2c_adapter *adap) > +static u32 i2c_sibyte_bit_func(struct i2c_adapter *adap) If you're renaming this then please drop the "bit" part in it, it's most likely coming from a copy-and-paste from i2c-algo-bit and has no meaning in the sibyte driver. > { > return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | > I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); > @@ -125,8 +186,8 @@ static u32 bit_func(struct i2c_adapter *adap) > /* -----exported algorithm data: ------------------------------------- */ > > static const struct i2c_algorithm i2c_sibyte_algo = { > - .smbus_xfer = smbus_xfer, > - .functionality = bit_func, > + .smbus_xfer = i2c_sibyte_smbus_xfer, > + .functionality = i2c_sibyte_bit_func, > }; > > /* > @@ -135,37 +196,121 @@ static const struct i2c_algorithm i2c_sibyte_algo = { > static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) > { > struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr; > + int err; > > - /* Register new adapter to i2c module... */ > - i2c_adap->algo = &i2c_sibyte_algo; > + adap->status = 0; > + init_waitqueue_head(&adap->wait); > + spin_lock_init(&adap->lock); > + > + csr = ioremap(adap->base, R_SMB_PEC + SMB_REGISTER_SPACING); > + if (!csr) { > + err = -ENOMEM; > + goto out; > + } > + adap->csr = csr; > > /* Set the requested frequency. */ > - csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); > - csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); > + __raw_writeq(speed, csr + R_SMB_FREQ); > + > + /* Clear any pending error interrupt. */ > + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); > + /* Disable interrupts. */ > + __raw_writeq(0, csr + R_SMB_CONTROL); > + mmiowb(); > + __raw_readq(csr + R_SMB_CONTROL); Shouldn't it be the other way around, disable interrupts first and then clear any pending one? Looks racy otherwise, but maybe it makes no difference in practice. > + > + err = request_irq(adap->irq, i2c_sibyte_interrupt, IRQF_SHARED, > + adap->name, i2c_adap); > + if (err < 0) > + goto out_unmap; > + > + /* Enable finish and error interrupts. */ > + __raw_writeq(M_SMB_FINISH_INTR | M_SMB_ERR_INTR, csr + R_SMB_CONTROL); > + > + /* Register new adapter to i2c module... */ > + err = i2c_add_numbered_adapter(i2c_adap); > + if (err < 0) > + goto out_unirq; > + > + return 0; > > - return i2c_add_numbered_adapter(i2c_adap); > +out_unirq: > + /* Disable interrupts. */ > + __raw_writeq(0, csr + R_SMB_CONTROL); > + mmiowb(); > + __raw_readq(csr + R_SMB_CONTROL); > + > + free_irq(adap->irq, i2c_adap); > + > + /* Clear any pending error interrupt. */ > + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); You may consider moving this block to a separate function, as it is duplicated in the i2c_sibyte_remove_bus() function below. > +out_unmap: > + iounmap(csr); > +out: > + return err; > } > > +static void i2c_sibyte_remove_bus(struct i2c_adapter *i2c_adap) > +{ > + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; > + void __iomem *csr = adap->csr; > + > + i2c_del_adapter(i2c_adap); > + > + /* Disable interrupts. */ > + __raw_writeq(0, csr + R_SMB_CONTROL); > + mmiowb(); > + __raw_readq(csr + R_SMB_CONTROL); > > -static struct i2c_algo_sibyte_data sibyte_board_data[2] = { > - { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, > - { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } > + free_irq(adap->irq, i2c_adap); > + > + /* Clear any pending error interrupt. */ > + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); > + > + iounmap(csr); > +} > + > +static struct i2c_algo_sibyte_data i2c_sibyte_board_data[2] = { > +#ifdef CONFIG_SIBYTE_SB1250 > + { > + .name = "sb1250-smbus-0", > + .base = A_SMB_0, > + .irq = K_INT_SMB_0, > + }, > + { > + .name = "sb1250-smbus-1", > + .base = A_SMB_1, > + .irq = K_INT_SMB_1, > + } > +#else > + { > + .name = "bcm1480-smbus-0", > + .base = A_SMB_0, > + .irq = K_BCM1480_INT_SMB_0, > + }, > + { > + .name = "bcm1480-smbus-1", > + .base = A_SMB_1, > + .irq = K_BCM1480_INT_SMB_1, > + } > +#endif > }; > > -static struct i2c_adapter sibyte_board_adapter[2] = { > +static struct i2c_adapter i2c_sibyte_board_adapter[2] = { > { > .owner = THIS_MODULE, > .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, > - .algo = NULL, > - .algo_data = &sibyte_board_data[0], > + .algo = &i2c_sibyte_algo, > + .algo_data = &i2c_sibyte_board_data[0], > .nr = 0, > .name = "SiByte SMBus 0", > }, > { > .owner = THIS_MODULE, > .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, > - .algo = NULL, > - .algo_data = &sibyte_board_data[1], > + .algo = &i2c_sibyte_algo, > + .algo_data = &i2c_sibyte_board_data[1], > .nr = 1, > .name = "SiByte SMBus 1", > }, > @@ -173,21 +318,32 @@ static struct i2c_adapter sibyte_board_adapter[2] = { > > static int __init i2c_sibyte_init(void) > { > + int err; > + > pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n"); > - if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0) > - return -ENODEV; > - if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], > - K_SMB_FREQ_400KHZ) < 0) { > - i2c_del_adapter(&sibyte_board_adapter[0]); > - return -ENODEV; > - } > + > + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[0], > + K_SMB_FREQ_100KHZ); > + if (err < 0) > + goto out; > + > + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[1], > + K_SMB_FREQ_400KHZ); > + if (err < 0) > + goto out_remove; > + > return 0; > + > +out_remove: > + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); > +out: > + return err; > } > > static void __exit i2c_sibyte_exit(void) > { > - i2c_del_adapter(&sibyte_board_adapter[0]); > - i2c_del_adapter(&sibyte_board_adapter[1]); > + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[1]); > + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); > } > > module_init(i2c_sibyte_init); Please address my concerns where you agree and send an updated patch. -- Jean Delvare ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <20110903103036.161616a5-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <20110903103036.161616a5-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> @ 2011-10-31 9:53 ` Jean Delvare [not found] ` <20111031105354.4b888e44-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Jean Delvare @ 2011-10-31 9:53 UTC (permalink / raw) To: Matt Turner Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki On Sat, 3 Sep 2011 10:30:36 +0200, Jean Delvare wrote: > Please address my concerns where you agree and send an updated patch. Matt, care to send an updated patch addressing my concerns? Otherwise it will be lost again. -- Jean Delvare ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <20111031105354.4b888e44-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <20111031105354.4b888e44-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> @ 2012-01-10 14:38 ` Jean Delvare 2012-01-10 15:31 ` Maciej W. Rozycki [not found] ` <20120110153834.531664db-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 2 replies; 30+ messages in thread From: Jean Delvare @ 2012-01-10 14:38 UTC (permalink / raw) To: Matt Turner Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki On Mon, 31 Oct 2011 10:53:54 +0100, Jean Delvare wrote: > On Sat, 3 Sep 2011 10:30:36 +0200, Jean Delvare wrote: > > Please address my concerns where you agree and send an updated patch. > > Matt, care to send an updated patch addressing my concerns? Otherwise > it will be lost again. It's been 3 more months. Matt (or anyone else who cares and has access to the hardware), please send an updated patch or I'll have to drop it. -- Jean Delvare ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts 2012-01-10 14:38 ` Jean Delvare @ 2012-01-10 15:31 ` Maciej W. Rozycki [not found] ` <20120110153834.531664db-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 1 sibling, 0 replies; 30+ messages in thread From: Maciej W. Rozycki @ 2012-01-10 15:31 UTC (permalink / raw) To: Jean Delvare Cc: Matt Turner, linux-i2c, linux-mips, Ralf Baechle, Guenter Roeck On Tue, 10 Jan 2012, Jean Delvare wrote: > > > Please address my concerns where you agree and send an updated patch. > > > > Matt, care to send an updated patch addressing my concerns? Otherwise > > it will be lost again. > > It's been 3 more months. Matt (or anyone else who cares and has access > to the hardware), please send an updated patch or I'll have to drop it. Thanks for nagging -- it seems unlikely I'll be able to have a look at it before February. If Matt or anyone else cannot get at it before myself and you have to drop the change, then just do what you have to and drop it. I'll try to resync with the current kernel as soon as I can, recheck my queue of outstanding patches and resend both this change and any other ones I'll consider necessary -- I reckon there were more than just this one. Thanks for your understanding and sorry about my recent lack of activity in this area. All the best in the New Year! :) Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <20120110153834.531664db-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <20120110153834.531664db-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> @ 2012-01-12 21:19 ` Matt Turner [not found] ` <CAEdQ38FpG11m50pwg2=tu1fJRRg=zixFKLsPmVPOzWNBCjbNBg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2012-01-12 21:19 UTC (permalink / raw) To: Jean Delvare Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck, Maciej W. Rozycki On Tue, Jan 10, 2012 at 9:38 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > On Mon, 31 Oct 2011 10:53:54 +0100, Jean Delvare wrote: >> On Sat, 3 Sep 2011 10:30:36 +0200, Jean Delvare wrote: >> > Please address my concerns where you agree and send an updated patch. >> >> Matt, care to send an updated patch addressing my concerns? Otherwise >> it will be lost again. > > It's been 3 more months. Matt (or anyone else who cares and has access > to the hardware), please send an updated patch or I'll have to drop it. > > -- > Jean Delvare I'll fix it up and resend the next time I'm working on the related mips stuff. It's hard to prioritize volunteer work for hardware you and two other people have. :) Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <CAEdQ38FpG11m50pwg2=tu1fJRRg=zixFKLsPmVPOzWNBCjbNBg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <CAEdQ38FpG11m50pwg2=tu1fJRRg=zixFKLsPmVPOzWNBCjbNBg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2012-03-31 6:23 ` Jean Delvare [not found] ` <20120331082346.26cc95cb-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Jean Delvare @ 2012-03-31 6:23 UTC (permalink / raw) To: Matt Turner, Maciej W. Rozycki Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck On Thu, 12 Jan 2012 16:19:49 -0500, Matt Turner wrote: > On Tue, Jan 10, 2012 at 9:38 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > > On Mon, 31 Oct 2011 10:53:54 +0100, Jean Delvare wrote: > >> On Sat, 3 Sep 2011 10:30:36 +0200, Jean Delvare wrote: > >> > Please address my concerns where you agree and send an updated patch. > >> > >> Matt, care to send an updated patch addressing my concerns? Otherwise > >> it will be lost again. > > > > It's been 3 more months. Matt (or anyone else who cares and has access > > to the hardware), please send an updated patch or I'll have to drop it. > > I'll fix it up and resend the next time I'm working on the related mips stuff. > > It's hard to prioritize volunteer work for hardware you and two other > people have. :) Matt, Maciej, does any of you have an updated patch ready by now? If I don't receive anything by the end of April I'll just drop it. -- Jean Delvare ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <20120331082346.26cc95cb-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <20120331082346.26cc95cb-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> @ 2012-03-31 12:11 ` Matt Turner [not found] ` <CAEdQ38Ez+8DudAaJY7HZu9jbisk_KMbBO5h=s+P4pjJ0Va-zWw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Matt Turner @ 2012-03-31 12:11 UTC (permalink / raw) To: Jean Delvare Cc: Maciej W. Rozycki, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck On Sat, Mar 31, 2012 at 2:23 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > On Thu, 12 Jan 2012 16:19:49 -0500, Matt Turner wrote: >> On Tue, Jan 10, 2012 at 9:38 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: >> > On Mon, 31 Oct 2011 10:53:54 +0100, Jean Delvare wrote: >> >> On Sat, 3 Sep 2011 10:30:36 +0200, Jean Delvare wrote: >> >> > Please address my concerns where you agree and send an updated patch. >> >> >> >> Matt, care to send an updated patch addressing my concerns? Otherwise >> >> it will be lost again. >> > >> > It's been 3 more months. Matt (or anyone else who cares and has access >> > to the hardware), please send an updated patch or I'll have to drop it. >> >> I'll fix it up and resend the next time I'm working on the related mips stuff. >> >> It's hard to prioritize volunteer work for hardware you and two other >> people have. :) > > Matt, Maciej, does any of you have an updated patch ready by now? If I > don't receive anything by the end of April I'll just drop it. I'll do my best to get you an updated patch. Thanks for keeping after me. Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <CAEdQ38Ez+8DudAaJY7HZu9jbisk_KMbBO5h=s+P4pjJ0Va-zWw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <CAEdQ38Ez+8DudAaJY7HZu9jbisk_KMbBO5h=s+P4pjJ0Va-zWw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2012-04-03 12:26 ` Maciej W. Rozycki 2012-06-30 16:35 ` Matt Turner 1 sibling, 0 replies; 30+ messages in thread From: Maciej W. Rozycki @ 2012-04-03 12:26 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck On Sat, 31 Mar 2012, Matt Turner wrote: > >> It's hard to prioritize volunteer work for hardware you and two other > >> people have. :) > > > > Matt, Maciej, does any of you have an updated patch ready by now? If I > > don't receive anything by the end of April I'll just drop it. > > I'll do my best to get you an updated patch. > > Thanks for keeping after me. And thanks for looking after the patches -- regrettably I still have no ETA on updating my Linux sources to a version that would let me work on upstream patches, sigh... I'll do my best to review or provide other feedback on these changes if needed though. Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <CAEdQ38Ez+8DudAaJY7HZu9jbisk_KMbBO5h=s+P4pjJ0Va-zWw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2012-04-03 12:26 ` Maciej W. Rozycki @ 2012-06-30 16:35 ` Matt Turner [not found] ` <CAEdQ38EDKndUcdBu1tZ_dOuhweVRW6aA=YKb6kUE3gUQJiwWoQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 1 sibling, 1 reply; 30+ messages in thread From: Matt Turner @ 2012-06-30 16:35 UTC (permalink / raw) To: Jean Delvare Cc: Maciej W. Rozycki, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck On Sat, Mar 31, 2012 at 8:11 AM, Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > On Sat, Mar 31, 2012 at 2:23 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: >> On Thu, 12 Jan 2012 16:19:49 -0500, Matt Turner wrote: >>> On Tue, Jan 10, 2012 at 9:38 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: >>> > On Mon, 31 Oct 2011 10:53:54 +0100, Jean Delvare wrote: >>> >> On Sat, 3 Sep 2011 10:30:36 +0200, Jean Delvare wrote: >>> >> > Please address my concerns where you agree and send an updated patch. >>> >> >>> >> Matt, care to send an updated patch addressing my concerns? Otherwise >>> >> it will be lost again. >>> > >>> > It's been 3 more months. Matt (or anyone else who cares and has access >>> > to the hardware), please send an updated patch or I'll have to drop it. >>> >>> I'll fix it up and resend the next time I'm working on the related mips stuff. >>> >>> It's hard to prioritize volunteer work for hardware you and two other >>> people have. :) >> >> Matt, Maciej, does any of you have an updated patch ready by now? If I >> don't receive anything by the end of April I'll just drop it. > > I'll do my best to get you an updated patch. > > Thanks for keeping after me. > > Matt Hi Jean, I'm not going to have time to do this. :( I had another look at the code, and I'm not sure I really understand it well enough to address your concerns. Good thing there are only about three users with this motherboard. Matt ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <CAEdQ38EDKndUcdBu1tZ_dOuhweVRW6aA=YKb6kUE3gUQJiwWoQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <CAEdQ38EDKndUcdBu1tZ_dOuhweVRW6aA=YKb6kUE3gUQJiwWoQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2012-07-19 21:01 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1207160208570.12288-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 0 siblings, 1 reply; 30+ messages in thread From: Maciej W. Rozycki @ 2012-07-19 21:01 UTC (permalink / raw) To: Matt Turner Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck On Sat, 30 Jun 2012, Matt Turner wrote: > I'm not going to have time to do this. :( > > I had another look at the code, and I'm not sure I really understand > it well enough to address your concerns. I'll try then, as soon as I can. > Good thing there are only about three users with this motherboard. Really? I've thought Debian used them for MIPS distribution builds if nobody else. AFAIK, ten years on and these systems (I mean the whole family) are still about the only ones reasonably widely available that provide performance decent enough for native use these days (yes, I did make serious use of an R3k DECstation natively once -- waiting for a GCC bootstrap to complete after the expected four weeks of computing time only to see it choke on a Makefile typo three weeks into was all but fun). Maciej ^ permalink raw reply [flat|nested] 30+ messages in thread
[parent not found: <alpine.LFD.2.00.1207160208570.12288-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org>]
* Re: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts [not found] ` <alpine.LFD.2.00.1207160208570.12288-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> @ 2012-12-18 12:08 ` Jean Delvare 0 siblings, 0 replies; 30+ messages in thread From: Jean Delvare @ 2012-12-18 12:08 UTC (permalink / raw) To: Maciej W. Rozycki, Matt Turner Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-mips-6z/3iImG2C8G8FEW9MqTrA, Ralf Baechle, Guenter Roeck On Thu, 19 Jul 2012 22:01:08 +0100 (BST), Maciej W. Rozycki wrote: > On Sat, 30 Jun 2012, Matt Turner wrote: > > > I'm not going to have time to do this. :( > > > > I had another look at the code, and I'm not sure I really understand > > it well enough to address your concerns. > > I'll try then, as soon as I can. I'm giving up on this one, sorry. I've been waiting for an update for over a year, this is simply too much. I just don't get why this patch was ever submitted if there was no intent to actually get it included. This has been a waste of many people's time :( -- Jean Delvare ^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH] I2C: SiByte: Convert the driver to make use of interrupts @ 2008-05-13 3:28 Maciej W. Rozycki 0 siblings, 0 replies; 30+ messages in thread From: Maciej W. Rozycki @ 2008-05-13 3:28 UTC (permalink / raw) To: Jean Delvare, Andrew Morton; +Cc: i2c, linux-mips, linux-kernel This is a rewrite of large parts of the driver mainly so that it uses SMBus interrupts to offload the CPU from busy-waiting on status inputs. As a part of the overhaul of the init and exit calls, all accesses to the hardware got converted to use accessory functions via an ioremap() cookie. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> --- This patch depends on patch-2.6.26-rc1-20080505-swarm-i2c-16 -- submitted as a part of the recent set of M41T80 RTC changes. Jean, please let me know if you prefer the ioremap() changes separately. Similarly, how about the -EINVAL/-EIO error codes? Also please note how I hesitated from adding second space after final full stops within comments. Maciej patch-2.6.26-rc1-20080505-sibyte-i2c-irq-5 diff -up --recursive --new-file linux-2.6.26-rc1-20080505.macro/drivers/i2c/busses/i2c-sibyte.c linux-2.6.26-rc1-20080505/drivers/i2c/busses/i2c-sibyte.c --- linux-2.6.26-rc1-20080505.macro/drivers/i2c/busses/i2c-sibyte.c 2008-05-11 02:25:56.000000000 +0000 +++ linux-2.6.26-rc1-20080505/drivers/i2c/busses/i2c-sibyte.c 2008-05-12 06:00:16.000000000 +0000 @@ -2,6 +2,7 @@ * Copyright (C) 2004 Steven J. Hill * Copyright (C) 2001,2002,2003 Broadcom Corporation * Copyright (C) 1995-2000 Simon G. Vogl + * Copyright (C) 2008 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,104 +19,159 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/errno.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/param.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/wait.h> #include <asm/io.h> +#include <asm/sibyte/sb1250_int.h> #include <asm/sibyte/sb1250_regs.h> #include <asm/sibyte/sb1250_smbus.h> struct i2c_algo_sibyte_data { - void *data; /* private data */ - int bus; /* which bus */ - void *reg_base; /* CSR base */ + wait_queue_head_t wait; /* IRQ queue */ + void __iomem *csr; /* mapped CSR handle */ + phys_t base; /* physical CSR base */ + char *name; /* IRQ handler name */ + spinlock_t lock; /* atomiser */ + int irq; /* IRQ line */ + int status; /* IRQ status */ }; -/* ----- global defines ----------------------------------------------- */ -#define SMB_CSR(a,r) ((long)(a->reg_base + r)) +static irqreturn_t i2c_sibyte_interrupt(int irq, void *dev_id) +{ + struct i2c_adapter *i2c_adap = dev_id; + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + u8 status; + + /* + * Ugh, no way to detect the finish interrupt, + * but if busy it is obviously not one. + */ + status = __raw_readq(csr + R_SMB_STATUS); + if ((status & (M_SMB_ERROR | M_SMB_BUSY)) == M_SMB_BUSY) + return IRQ_NONE; + + /* + * Clear the error interrupt (write 1 to clear); + * the finish interrupt was cleared by the read above. + */ + __raw_writeq(status, csr + R_SMB_STATUS); + + /* Post the status. */ + spin_lock_irq(&adap->lock); + adap->status = status & (M_SMB_ERROR_TYPE | M_SMB_ERROR | M_SMB_BUSY); + wake_up(&adap->wait); + spin_unlock_irq(&adap->lock); + + return IRQ_HANDLED; +} -static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) +static s32 i2c_sibyte_smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, + unsigned short cflags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) { struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + unsigned long flags; int data_bytes = 0; int error; - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; + spin_lock_irqsave(&adap->lock, flags); + + if (adap->status < 0) { + error = -EIO; + goto out_unlock; + } switch (size) { case I2C_SMBUS_QUICK: - csr_out32((V_SMB_ADDR(addr) | - (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | - V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | + (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | + V_SMB_TT_QUICKCMD, + csr + R_SMB_START); break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE, + csr + R_SMB_START); data_bytes = 1; } else { - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE, + csr + R_SMB_START); } break; case I2C_SMBUS_BYTE_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE, + csr + R_SMB_START); data_bytes = 1; } else { - csr_out32(V_SMB_LB(data->byte), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_LB(data->byte), csr + R_SMB_DATA); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, + csr + R_SMB_START); } break; case I2C_SMBUS_WORD_DATA: - csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); + __raw_writeq(V_SMB_CMD(command), csr + R_SMB_CMD); if (read_write == I2C_SMBUS_READ) { - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE, + csr + R_SMB_START); data_bytes = 2; } else { - csr_out32(V_SMB_LB(data->word & 0xff), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32(V_SMB_MB(data->word >> 8), - SMB_CSR(adap, R_SMB_DATA)); - csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), - SMB_CSR(adap, R_SMB_START)); + __raw_writeq(V_SMB_LB(data->word & 0xff), + csr + R_SMB_DATA); + __raw_writeq(V_SMB_MB(data->word >> 8), + csr + R_SMB_DATA); + __raw_writeq(V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE, + csr + R_SMB_START); } break; default: - return -1; /* XXXKW better error code? */ + error = -EINVAL; + goto out_unlock; } + mmiowb(); + __raw_readq(csr + R_SMB_START); + adap->status = -1; + + spin_unlock_irqrestore(&adap->lock, flags); - while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) - ; + wait_event_timeout(adap->wait, (adap->status >= 0), HZ); - error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); - if (error & M_SMB_ERROR) { - /* Clear error bit by writing a 1 */ - csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); - return -1; /* XXXKW better error code? */ + spin_lock_irqsave(&adap->lock, flags); + + if (adap->status < 0 || (adap->status & (M_SMB_ERROR | M_SMB_BUSY))) { + error = -EIO; + goto out_unlock; } if (data_bytes == 1) - data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; + data->byte = __raw_readq(csr + R_SMB_DATA) & 0xff; if (data_bytes == 2) - data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; + data->word = __raw_readq(csr + R_SMB_DATA) & 0xffff; - return 0; + error = 0; + +out_unlock: + spin_unlock_irqrestore(&adap->lock, flags); + + return error; } -static u32 bit_func(struct i2c_adapter *adap) +static u32 i2c_sibyte_bit_func(struct i2c_adapter *adap) { return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); @@ -125,8 +181,8 @@ static u32 bit_func(struct i2c_adapter * /* -----exported algorithm data: ------------------------------------- */ static const struct i2c_algorithm i2c_sibyte_algo = { - .smbus_xfer = smbus_xfer, - .functionality = bit_func, + .smbus_xfer = i2c_sibyte_smbus_xfer, + .functionality = i2c_sibyte_bit_func, }; /* @@ -135,30 +191,101 @@ static const struct i2c_algorithm i2c_si static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) { struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr; + int err; - /* Register new adapter to i2c module... */ - i2c_adap->algo = &i2c_sibyte_algo; + adap->status = 0; + init_waitqueue_head(&adap->wait); + spin_lock_init(&adap->lock); + + csr = ioremap(adap->base, R_SMB_PEC + SMB_REGISTER_SPACING); + if (!csr) { + err = -ENOMEM; + goto out; + } + adap->csr = csr; /* Set the requested frequency. */ - csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); - csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); + __raw_writeq(speed, csr + R_SMB_FREQ); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + err = request_irq(adap->irq, i2c_sibyte_interrupt, IRQF_SHARED, + adap->name, i2c_adap); + if (err < 0) + goto out_unmap; - return i2c_add_numbered_adapter(i2c_adap); + /* Enable finish and error interrupts. */ + __raw_writeq(M_SMB_FINISH_INTR | M_SMB_ERR_INTR, csr + R_SMB_CONTROL); + + /* Register new adapter to i2c module... */ + err = i2c_add_numbered_adapter(i2c_adap); + if (err < 0) + goto out_unirq; + + return 0; + +out_unirq: + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + free_irq(adap->irq, i2c_adap); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); +out_unmap: + iounmap(csr); +out: + return err; } +static void i2c_sibyte_remove_bus(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; + void __iomem *csr = adap->csr; + + i2c_del_adapter(i2c_adap); + + /* Disable interrupts. */ + __raw_writeq(0, csr + R_SMB_CONTROL); + mmiowb(); + __raw_readq(csr + R_SMB_CONTROL); + + free_irq(adap->irq, i2c_adap); + + /* Clear any pending error interrupt. */ + __raw_writeq(__raw_readq(csr + R_SMB_STATUS), csr + R_SMB_STATUS); + + iounmap(csr); +} -static struct i2c_algo_sibyte_data sibyte_board_data[2] = { - { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, - { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } +static struct i2c_algo_sibyte_data i2c_sibyte_board_data[2] = { + { + .name = "sb1250-smbus-0", + .base = A_SMB_0, + .irq = K_INT_SMB_0, + }, + { + .name = "sb1250-smbus-1", + .base = A_SMB_1, + .irq = K_INT_SMB_1, + } }; -static struct i2c_adapter sibyte_board_adapter[2] = { +static struct i2c_adapter i2c_sibyte_board_adapter[2] = { { .owner = THIS_MODULE, .id = I2C_HW_SIBYTE, .class = I2C_CLASS_HWMON, - .algo = NULL, - .algo_data = &sibyte_board_data[0], + .algo = &i2c_sibyte_algo, + .algo_data = &i2c_sibyte_board_data[0], .nr = 0, .name = "SiByte SMBus 0", }, @@ -166,8 +293,8 @@ static struct i2c_adapter sibyte_board_a .owner = THIS_MODULE, .id = I2C_HW_SIBYTE, .class = I2C_CLASS_HWMON, - .algo = NULL, - .algo_data = &sibyte_board_data[1], + .algo = &i2c_sibyte_algo, + .algo_data = &i2c_sibyte_board_data[1], .nr = 1, .name = "SiByte SMBus 1", }, @@ -175,21 +302,32 @@ static struct i2c_adapter sibyte_board_a static int __init i2c_sibyte_init(void) { + int err; + pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n"); - if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0) - return -ENODEV; - if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], - K_SMB_FREQ_400KHZ) < 0) { - i2c_del_adapter(&sibyte_board_adapter[0]); - return -ENODEV; - } + + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[0], + K_SMB_FREQ_100KHZ); + if (err < 0) + goto out; + + err = i2c_sibyte_add_bus(&i2c_sibyte_board_adapter[1], + K_SMB_FREQ_400KHZ); + if (err < 0) + goto out_remove; + return 0; + +out_remove: + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); +out: + return err; } static void __exit i2c_sibyte_exit(void) { - i2c_del_adapter(&sibyte_board_adapter[0]); - i2c_del_adapter(&sibyte_board_adapter[1]); + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[1]); + i2c_sibyte_remove_bus(&i2c_sibyte_board_adapter[0]); } module_init(i2c_sibyte_init); ^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2012-12-18 12:08 UTC | newest] Thread overview: 30+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-12-06 6:38 [PATCH] I2C: SiByte: Convert the driver to make use of interrupts Matt Turner [not found] ` <1291617494-18430-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2010-12-06 14:59 ` Guenter Roeck 2010-12-06 17:30 ` Guenter Roeck [not found] ` <20101206173040.GA18372-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> 2010-12-06 17:40 ` Matt Turner [not found] ` <AANLkTikGgfBuj086eRvy4VzzyE2suJCL9z=SfmOiFiPx-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2010-12-06 18:02 ` Guenter Roeck 2010-12-06 18:04 ` Matt Turner 2010-12-06 17:56 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1012061739200.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 2010-12-06 18:02 ` Matt Turner [not found] ` <AANLkTikWRsgHao_eb4W47b=E4vm6z=hi36JE_VBtD6Rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2010-12-07 2:26 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1012070148050.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 2010-12-07 5:14 ` Guenter Roeck [not found] ` <20101207051438.GA20144-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> 2010-12-07 14:30 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1012070740130.17185-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 2010-12-07 14:41 ` Guenter Roeck 2010-12-07 6:23 ` Guenter Roeck -- strict thread matches above, loose matches on Subject: below -- 2011-08-18 23:43 Matt Turner [not found] ` <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2011-08-22 20:02 ` Guenter Roeck 2011-08-24 15:36 ` Matt Turner [not found] ` <CAEdQ38E6qqVAKC1MkAWto5yeU9N2uoyGY1Y5431kNUNL_yc8EA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2011-09-02 13:21 ` Jean Delvare 2011-09-02 13:35 ` Maciej W. Rozycki 2011-09-03 8:30 ` Jean Delvare [not found] ` <20110903103036.161616a5-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 2011-10-31 9:53 ` Jean Delvare [not found] ` <20111031105354.4b888e44-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 2012-01-10 14:38 ` Jean Delvare 2012-01-10 15:31 ` Maciej W. Rozycki [not found] ` <20120110153834.531664db-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 2012-01-12 21:19 ` Matt Turner [not found] ` <CAEdQ38FpG11m50pwg2=tu1fJRRg=zixFKLsPmVPOzWNBCjbNBg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2012-03-31 6:23 ` Jean Delvare [not found] ` <20120331082346.26cc95cb-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org> 2012-03-31 12:11 ` Matt Turner [not found] ` <CAEdQ38Ez+8DudAaJY7HZu9jbisk_KMbBO5h=s+P4pjJ0Va-zWw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2012-04-03 12:26 ` Maciej W. Rozycki 2012-06-30 16:35 ` Matt Turner [not found] ` <CAEdQ38EDKndUcdBu1tZ_dOuhweVRW6aA=YKb6kUE3gUQJiwWoQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2012-07-19 21:01 ` Maciej W. Rozycki [not found] ` <alpine.LFD.2.00.1207160208570.12288-FBDaDh2CBnQu/uO211tRtWD2FQJk+8+b@public.gmane.org> 2012-12-18 12:08 ` Jean Delvare 2008-05-13 3:28 Maciej W. Rozycki
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).