From: Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org,
Ralf Baechle <ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>,
Guenter Roeck
<guenter.roeck-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org>,
"Maciej W. Rozycki"
<macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>,
Matt Turner <mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Subject: [PATCH] I2C: SiByte: Convert the driver to make use of interrupts
Date: Thu, 18 Aug 2011 19:43:11 -0400 [thread overview]
Message-ID: <1313710991-3596-1-git-send-email-mattst88@gmail.com> (raw)
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
next reply other threads:[~2011-08-18 23:43 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-18 23:43 Matt Turner [this message]
[not found] ` <1313710991-3596-1-git-send-email-mattst88-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2011-08-22 20:02 ` [PATCH] I2C: SiByte: Convert the driver to make use of interrupts 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
-- strict thread matches above, loose matches on Subject: below --
2010-12-06 6:38 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
2008-05-13 3:28 Maciej W. Rozycki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1313710991-3596-1-git-send-email-mattst88@gmail.com \
--to=mattst88-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
--cc=guenter.roeck-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org \
--cc=khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org \
--cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org \
--cc=macro-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org \
--cc=ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).