From: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
To: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>,
Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>,
Ian Campbell
<ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>,
Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>,
Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>,
Greg Kroah-Hartman
<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>,
Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
Meng Zhang
<kevin-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@public.gmane.org>,
shuge-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@public.gmane.org,
kevin.z.m.zh-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
Subject: [PATCH v3 4/8] rsb: sunxi: Add driver for Allwinner Reduced Serial Bus controller
Date: Wed, 19 Aug 2015 12:20:05 +0800 [thread overview]
Message-ID: <1439958009-14056-5-git-send-email-wens@csie.org> (raw)
In-Reply-To: <1439958009-14056-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/rsb/Kconfig | 15 ++
drivers/rsb/Makefile | 2 +
drivers/rsb/rsb-sunxi.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 458 insertions(+)
create mode 100644 drivers/rsb/rsb-sunxi.c
diff --git a/drivers/rsb/Kconfig b/drivers/rsb/Kconfig
index 6642e1db6d98..54a28a39e0e2 100644
--- a/drivers/rsb/Kconfig
+++ b/drivers/rsb/Kconfig
@@ -9,3 +9,18 @@ menuconfig RSB
Integrated Circuits (PMIC) or other peripherals.
These are commonly seen on newer Allwinner SoCs and X-Powers ICs.
+
+if RSB
+
+config RSB_SUNXI
+ tristate "Allwinner RSB Controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ default MACH_SUN8I || MACH_SUN9I
+ help
+ If you say yes to this option, support will be included for the
+ built-in RSB controller on Allwinner sun8i/sun9i family SoCs.
+
+ This is required for communicating with X-Powers PMICs and other
+ devices that have the RSB interface.
+
+endif
diff --git a/drivers/rsb/Makefile b/drivers/rsb/Makefile
index 6fe56526fbf3..31cd615f7e58 100644
--- a/drivers/rsb/Makefile
+++ b/drivers/rsb/Makefile
@@ -2,3 +2,5 @@
# Makefile for kernel RSB framework.
#
obj-$(CONFIG_RSB) += rsb-core.o
+
+obj-$(CONFIG_RSB_SUNXI) += rsb-sunxi.o
diff --git a/drivers/rsb/rsb-sunxi.c b/drivers/rsb/rsb-sunxi.c
new file mode 100644
index 000000000000..07b24291fe4d
--- /dev/null
+++ b/drivers/rsb/rsb-sunxi.c
@@ -0,0 +1,441 @@
+/*
+ * RSB (Reduced Serial Bus) driver.
+ *
+ * Author: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * The RSB controller looks like an SMBus controller which only supports
+ * byte and word data transfers. But, it differs from standard SMBus
+ * protocol on several aspects:
+ * - it uses addresses set at runtime to address slaves. Runtime addresses
+ * are sent to slaves using their 12bit hardware addresses. Up to 15
+ * runtime addresses are available.
+ * - it adds a parity bit every 8bits of data and address for read and
+ * write accesses; this replaces the ack bit
+ * - only one read access is required to read a byte (instead of a write
+ * followed by a read access in standard SMBus protocol)
+ * - there's no Ack bit after each read access
+ *
+ * This means this bus cannot be used to interface with standard SMBus
+ * devices. Devices known to support this interface include the AXP223,
+ * AXP809, and AXP806 PMICs, and the AC100 audio codec, all from X-Powers.
+ *
+ * A description of the operation and wire protocol can be found in the
+ * RSB section of Allwinner's A80 user manual, which can be found at
+ *
+ * https://github.com/allwinner-zh/documents/tree/master/A80
+ *
+ * This document is officially released by Allwinner.
+ *
+ * This driver is based on i2c-sun6i-p2wi.c, the P2WI bus driver.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/rsb.h>
+
+/* RSB registers */
+#define RSB_CTRL 0x0 /* Global control */
+#define RSB_CCR 0x4 /* Clock control */
+#define RSB_INTE 0x8 /* Interrupt controls */
+#define RSB_INTS 0xc /* Interrupt status */
+#define RSB_ADDR 0x10 /* Address to send with read/write command */
+#define RSB_DATA 0x1c /* Data to read/write */
+#define RSB_LCR 0x24 /* Line control */
+#define RSB_DMCR 0x28 /* Device mode (init) control */
+#define RSB_CMD 0x2c /* RSB Command */
+#define RSB_DAR 0x30 /* Device address / runtime address */
+
+/* CTRL fields */
+#define RSB_CTRL_START_TRANS BIT(7)
+#define RSB_CTRL_ABORT_TRANS BIT(6)
+#define RSB_CTRL_GLOBAL_INT_ENB BIT(1)
+#define RSB_CTRL_SOFT_RST BIT(0)
+
+/* CLK CTRL fields */
+#define RSB_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8)
+#define RSB_CCR_MAX_CLK_DIV 0xff
+#define RSB_CCR_CLK_DIV(v) ((v) & RSB_CCR_MAX_CLK_DIV)
+
+/* STATUS fields */
+#define RSB_INTS_TRANS_ERR_ACK BIT(16)
+#define RSB_INTS_TRANS_ERR_DATA_BIT(v) (((v) >> 8) & 0xf)
+#define RSB_INTS_TRANS_ERR_DATA GENMASK(11, 8)
+#define RSB_INTS_LOAD_BSY BIT(2)
+#define RSB_INTS_TRANS_ERR BIT(1)
+#define RSB_INTS_TRANS_OVER BIT(0)
+
+/* LINE CTRL fields*/
+#define RSB_LCR_SCL_STATE BIT(5)
+#define RSB_LCR_SDA_STATE BIT(4)
+#define RSB_LCR_SCL_CTL BIT(3)
+#define RSB_LCR_SCL_CTL_EN BIT(2)
+#define RSB_LCR_SDA_CTL BIT(1)
+#define RSB_LCR_SDA_CTL_EN BIT(0)
+
+/* DEVICE MODE CTRL field values */
+#define RSB_DMCR_DEVICE_START BIT(31)
+#define RSB_DMCR_MODE_DATA (0x7c << 16)
+#define RSB_DMCR_MODE_REG (0x3e << 8)
+#define RSB_DMCR_DEV_ADDR 0x00
+
+/* CMD values */
+#define RSB_CMD_RD8 0x8b
+#define RSB_CMD_RD16 0x9c
+#define RSB_CMD_RD32 0xa6
+#define RSB_CMD_WR8 0x4e
+#define RSB_CMD_WR16 0x59
+#define RSB_CMD_WR32 0x63
+#define RSB_CMD_STRA 0xe8
+
+/* DAR fields */
+#define RSB_DAR_RTA(v) (((v) & 0xff) << 16)
+#define RSB_DAR_DA(v) ((v) & 0xffff)
+
+#define RSB_MAX_FREQ 20000000
+
+#define RSB_CTRL_NAME "sunxi-rsb"
+
+struct rsb {
+ struct rsb_controller *ctrl;
+ void __iomem *regs;
+ struct clk *clk;
+ struct reset_control *rstc;
+ struct completion complete;
+ unsigned int status;
+};
+
+static irqreturn_t rsb_interrupt(int irq, void *dev_id)
+{
+ struct rsb *rsb = dev_id;
+ u32 status;
+
+ /* Clear interrupts */
+ status = readl(rsb->regs + RSB_INTS);
+ rsb->status = status;
+ writel(status, rsb->regs + RSB_INTS);
+
+ complete(&rsb->complete);
+
+ return IRQ_HANDLED;
+}
+
+/* common code that starts a transfer */
+static int rsb_run_xfer(struct rsb *rsb)
+{
+ if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) {
+ dev_dbg(&rsb->ctrl->dev, "RSB transfer still in progress\n");
+ return -EBUSY;
+ }
+
+ reinit_completion(&rsb->complete);
+
+ writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
+ rsb->regs + RSB_INTE);
+ writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB,
+ rsb->regs + RSB_CTRL);
+
+ if (!wait_for_completion_io_timeout(&rsb->complete,
+ msecs_to_jiffies(100))) {
+ dev_dbg(&rsb->ctrl->dev, "RSB timeout\n");
+
+ /* abort the transfer */
+ writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL);
+
+ /* clear any interrupt flags */
+ writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS);
+
+ return -ETIMEDOUT;
+ }
+
+ if (rsb->status & RSB_INTS_LOAD_BSY) {
+ dev_dbg(&rsb->ctrl->dev, "RSB busy\n");
+ return -EBUSY;
+ }
+
+ if (rsb->status & RSB_INTS_TRANS_ERR_ACK) {
+ dev_dbg(&rsb->ctrl->dev, "RSB slave nack\n");
+ return -EINVAL;
+ }
+
+ if (rsb->status & RSB_INTS_TRANS_ERR_DATA) {
+ dev_dbg(&rsb->ctrl->dev, "RSB transfer data error\n");
+ return -EIO;
+ }
+
+ /* This should be covered by the above 2 cases */
+ if (rsb->status & RSB_INTS_TRANS_ERR) {
+ dev_dbg(&rsb->ctrl->dev, "bus transfer error\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int rsb_read_cmd(struct rsb_controller *ctrl, u8 rtaddr,
+ u8 addr, u32 *buf, size_t len)
+{
+ struct rsb *rsb = rsb_controller_get_drvdata(ctrl);
+ u32 cmd;
+ int ret;
+
+ if (!buf)
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ cmd = RSB_CMD_RD8;
+ break;
+ case 2:
+ cmd = RSB_CMD_RD16;
+ break;
+ case 4:
+ cmd = RSB_CMD_RD32;
+ break;
+ default:
+ dev_err(&ctrl->dev, "Invalid access width: %d", len);
+ return -EINVAL;
+ }
+
+ writel(addr, rsb->regs + RSB_ADDR);
+ writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR);
+ writel(cmd, rsb->regs + RSB_CMD);
+
+ ret = rsb_run_xfer(rsb);
+ if (ret)
+ return ret;
+
+ *buf = readl(rsb->regs + RSB_DATA);
+
+ return 0;
+}
+
+static int rsb_write_cmd(struct rsb_controller *ctrl, u8 rtaddr,
+ u8 addr, const u32 *buf, size_t len)
+{
+ struct rsb *rsb = rsb_controller_get_drvdata(ctrl);
+ u32 cmd;
+
+ if (!buf)
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ cmd = RSB_CMD_WR8;
+ break;
+ case 2:
+ cmd = RSB_CMD_WR16;
+ break;
+ case 4:
+ cmd = RSB_CMD_WR32;
+ break;
+ default:
+ dev_err(&ctrl->dev, "Invalid access width: %d", len);
+ return -EINVAL;
+ }
+
+ writel(addr, rsb->regs + RSB_ADDR);
+ writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR);
+ writel(*buf, rsb->regs + RSB_DATA);
+ writel(cmd, rsb->regs + RSB_CMD);
+
+ return rsb_run_xfer(rsb);
+}
+
+static int rsb_rtsaddr_cmd(struct rsb_controller *ctrl, u16 hwaddr, u8 rtaddr)
+{
+ struct rsb *rsb = rsb_controller_get_drvdata(ctrl);
+
+ /* setup command parameters */
+ writel(RSB_DAR_RTA(rtaddr) | RSB_DAR_DA(hwaddr), rsb->regs + RSB_DAR);
+ writel(RSB_CMD_STRA, rsb->regs + RSB_CMD);
+
+ /* send command */
+ return rsb_run_xfer(rsb);
+}
+
+static int rsb_init_cmd(struct rsb_controller *ctrl)
+{
+ struct rsb *rsb = rsb_controller_get_drvdata(ctrl);
+ int reg;
+
+ /* send init sequence */
+ writel(RSB_DMCR_DEVICE_START | RSB_DMCR_MODE_DATA |
+ RSB_DMCR_MODE_REG | RSB_DMCR_DEV_ADDR, rsb->regs + RSB_DMCR);
+
+ readl_poll_timeout(rsb->regs + RSB_DMCR, reg,
+ !(reg & RSB_DMCR_DEVICE_START), 100, 250000);
+ if (reg & RSB_DMCR_DEVICE_START)
+ dev_warn(&ctrl->dev, "send init sequence timeout\n");
+
+ /* clear any interrupt flags */
+ writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS);
+
+ return 0;
+}
+
+static const struct of_device_id rsb_of_match_table[] = {
+ { .compatible = "allwinner,sun8i-a23-rsb" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rsb_of_match_table);
+
+static int rsb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct resource *r;
+ struct rsb_controller *ctrl;
+ struct rsb *rsb;
+ unsigned long parent_clk_freq;
+ u32 clk_freq = 100000;
+ int clk_div;
+ int irq;
+ int ret;
+ u32 reg;
+
+ of_property_read_u32(np, "clock-frequency", &clk_freq);
+ if (clk_freq > RSB_MAX_FREQ) {
+ dev_err(dev,
+ "clock-frequency (%u Hz) is too high (max = 20MHz)",
+ clk_freq);
+ return -EINVAL;
+ }
+
+ ctrl = rsb_controller_alloc(dev, sizeof(*rsb));
+ if (!ctrl)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ctrl);
+
+ /* set callbacks */
+ ctrl->init_cmd = rsb_init_cmd;
+ ctrl->rtsaddr_cmd = rsb_rtsaddr_cmd;
+ ctrl->read_cmd = rsb_read_cmd;
+ ctrl->write_cmd = rsb_write_cmd;
+
+ rsb = rsb_controller_get_drvdata(ctrl);
+ rsb->ctrl = ctrl;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rsb->regs = devm_ioremap_resource(dev, r);
+ if (IS_ERR(rsb->regs)) {
+ ret = PTR_ERR(rsb->regs);
+ goto err_rsb_controller_put;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to retrieve irq: %d\n", irq);
+ ret = irq;
+ goto err_rsb_controller_put;
+ }
+
+ rsb->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(rsb->clk)) {
+ ret = PTR_ERR(rsb->clk);
+ dev_err(dev, "failed to retrieve clk: %d\n", ret);
+ goto err_rsb_controller_put;
+ }
+
+ ret = clk_prepare_enable(rsb->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clk: %d\n", ret);
+ goto err_rsb_controller_put;
+ }
+
+ parent_clk_freq = clk_get_rate(rsb->clk);
+
+ rsb->rstc = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(rsb->rstc)) {
+ ret = PTR_ERR(rsb->rstc);
+ dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ ret = reset_control_deassert(rsb->rstc);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset line: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ init_completion(&rsb->complete);
+
+ /* reset the controller */
+ writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL);
+ readl_poll_timeout(rsb->regs + RSB_CTRL, reg,
+ !(reg & RSB_CTRL_SOFT_RST), 1000, 100000);
+
+ clk_div = parent_clk_freq / clk_freq;
+ if (!clk_div) {
+ dev_warn(dev,
+ "clock-frequency is too high, setting it to %lu Hz\n",
+ parent_clk_freq);
+ clk_div = 1;
+ } else if (clk_div > RSB_CCR_MAX_CLK_DIV + 1) {
+ dev_warn(dev,
+ "clock-frequency is too low, setting it to %lu Hz\n",
+ parent_clk_freq / (RSB_CCR_MAX_CLK_DIV + 1));
+ clk_div = RSB_CCR_MAX_CLK_DIV + 1;
+ }
+
+ writel(RSB_CCR_SDA_OUT_DELAY(1) | RSB_CCR_CLK_DIV(clk_div - 1),
+ rsb->regs + RSB_CCR);
+
+ ret = devm_request_irq(dev, irq, rsb_interrupt, 0, RSB_CTRL_NAME, rsb);
+ if (ret) {
+ dev_err(dev, "can't register interrupt handler irq%d: %d\n",
+ irq, ret);
+ goto err_reset_assert;
+ }
+
+ ret = rsb_controller_add(ctrl);
+ if (!ret)
+ return 0;
+
+err_reset_assert:
+ reset_control_assert(rsb->rstc);
+
+err_clk_disable:
+ clk_disable_unprepare(rsb->clk);
+
+err_rsb_controller_put:
+ rsb_controller_put(ctrl);
+
+ return ret;
+}
+
+static int rsb_remove(struct platform_device *pdev)
+{
+ struct rsb_controller *ctrl = platform_get_drvdata(pdev);
+ struct rsb *rsb = rsb_controller_get_drvdata(ctrl);
+
+ rsb_controller_remove(ctrl);
+ reset_control_assert(rsb->rstc);
+ clk_disable_unprepare(rsb->clk);
+
+ return 0;
+}
+
+static struct platform_driver rsb_driver = {
+ .probe = rsb_probe,
+ .remove = rsb_remove,
+ .driver = {
+ .name = "rsb-sunxi",
+ .of_match_table = rsb_of_match_table,
+ },
+};
+module_platform_driver(rsb_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>");
+MODULE_DESCRIPTION("Allwinner RSB driver");
+MODULE_LICENSE("GPL v2");
--
2.5.0
next prev parent reply other threads:[~2015-08-19 4:20 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-19 4:20 [PATCH v3 0/8] ARM: sunxi: Add Reduced Serial Bus support Chen-Yu Tsai
[not found] ` <1439958009-14056-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-08-19 4:20 ` [PATCH v3 1/8] rsb: Add generic Reduced Serial Bus (RSB) controller binding documentation Chen-Yu Tsai
[not found] ` <1439958009-14056-2-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-08-20 15:08 ` Maxime Ripard
2015-08-20 15:58 ` Chen-Yu Tsai
[not found] ` <CAGb2v65jnU859gQG0orb9M9pR6nKcth9EPcgmmR5fckdHxngrQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-08-20 21:24 ` Maxime Ripard
2015-08-23 22:43 ` Rob Herring
[not found] ` <CAL_JsqJA6MEtnF35ThPDgVmEZHyui39-HLsefWPQ1tzzfLAW3w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-09-14 7:32 ` Chen-Yu Tsai
2015-08-19 4:20 ` [PATCH v3 2/8] rsb: sunxi: Add Allwinner Reduced Serial Bus (RSB) controller bindings Chen-Yu Tsai
2015-08-19 4:20 ` [PATCH v3 3/8] rsb: Linux driver framework for Reduced Serial Bus (RSB) Chen-Yu Tsai
[not found] ` <1439958009-14056-4-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-08-20 17:05 ` Mark Brown
2015-08-19 4:20 ` Chen-Yu Tsai [this message]
2015-08-19 4:20 ` [PATCH v3 5/8] regmap: rsb: Add support for Reduced Serial Bus (RSB) based regmaps Chen-Yu Tsai
2015-08-19 4:20 ` [PATCH v3 6/8] ARM: dts: sun8i: Add Reduced Serial Bus controller device node to A23/A33 dtsi Chen-Yu Tsai
2015-08-19 4:20 ` [PATCH v3 7/8] ARM: dts: sun8i: ippo-q8h-v5: Enable Reduced Serial Bus controller Chen-Yu Tsai
2015-08-19 4:20 ` [PATCH v3 8/8] ARM: dts: sun8i: sinlinx-sina33: " Chen-Yu Tsai
2015-08-19 16:32 ` [PATCH v3 0/8] ARM: sunxi: Add Reduced Serial Bus support Mark Brown
[not found] ` <20150819163232.GS10748-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-08-20 1:59 ` Chen-Yu Tsai
[not found] ` <CAGb2v66X-CMQiS1dNqhwamTsVbnf+7siSTV3xGwn-C91Zhw3uA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-08-20 17:02 ` Mark Brown
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=1439958009-14056-5-git-send-email-wens@csie.org \
--to=wens-jday2fn1rrm@public.gmane.org \
--cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
--cc=gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org \
--cc=hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
--cc=ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org \
--cc=kevin-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@public.gmane.org \
--cc=kevin.z.m.zh-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org \
--cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
--cc=maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org \
--cc=pawel.moll-5wv7dgnIgG8@public.gmane.org \
--cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=shuge-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@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).