* [PATCH v2 1/2] i2c: qup: Add device tree bindings information
[not found] ` <1389659437-16406-2-git-send-email-bjorn.andersson@sonymobile.com>
@ 2014-01-14 8:57 ` Ivan T. Ivanov
2014-01-16 23:20 ` Bjorn Andersson
0 siblings, 1 reply; 9+ messages in thread
From: Ivan T. Ivanov @ 2014-01-14 8:57 UTC (permalink / raw)
To: linux-arm-kernel
Thanks Bjorn,
I have prepared second version, but never send it out :-).
One thing suggested by Mark was missed in this version.
On Mon, 2014-01-13 at 16:30 -0800, Bjorn Andersson wrote:
> From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
>
> The Qualcomm Universal Peripherial (QUP) wraps I2C mini-core and
> provide input and output FIFO's for it. I2C controller can operate
> as master with supported bus speeds of 100Kbps and 400Kbps.
>
> Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
> [bjorn: reformulated part of binding description and cleaned up example]
> Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
> ---
> .../devicetree/bindings/i2c/qcom,i2c-qup.txt | 41 ++++++++++++++++++++++
> 1 file changed, 41 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt
>
> diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt b/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt
> new file mode 100644
> index 0000000..a99711b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt
> @@ -0,0 +1,41 @@
> +Qualcomm Universal Peripheral (QUP) I2C controller
> +
> +Required properties:
> + - compatible: Should be "qcom,i2c-qup".
> + - reg: Should contain QUP register address and length.
> + - interrupts: Should contain I2C interrupt.
> +
> + - clocks: Should contain the core clock and the AHB clock.
+ - clocks: a list of phandle + clock-specifier pairs for each entry in
+ clock-names
> + - clock-names: Should be "core" for the core clock and "iface" for the
> + AHB clock.
> +
> + - #address-cells: Should be <1> Address cells for i2c device address
> + - #size-cells: Should be <0> as i2c addresses have no size component
> +
> +Optional properties:
> + - clock-frequency: Should specify the desired i2c bus clock frequency in Hz,
> + default is 100kHz if omitted.
> +
> +Child nodes should conform to i2c bus binding.
> +
> +Example:
> +
> + i2c2: i2c at f9924000 {
> + compatible = "qcom,i2c-qup";
> + reg = <0xf9924000 0x1000>;
> + interrupts = <0 96 0>;
> +
> + clocks = <&gcc_blsp1_qup2_i2c_apps_clk>, <&gcc_blsp1_ahb_clk>;
In the light of the latest patches from Stephen, this could be
+ clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
Regards,
Ivan
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller
[not found] ` <1389659437-16406-3-git-send-email-bjorn.andersson@sonymobile.com>
@ 2014-01-14 13:03 ` Ivan T. Ivanov
2014-01-15 16:46 ` Stephen Boyd
1 sibling, 0 replies; 9+ messages in thread
From: Ivan T. Ivanov @ 2014-01-14 13:03 UTC (permalink / raw)
To: linux-arm-kernel
Hi Bjorn,
Just two comments.
On Mon, 2014-01-13 at 16:30 -0800, Bjorn Andersson wrote:
> From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
>
> This bus driver supports the QUP i2c hardware controller in the Qualcomm
> MSM SOCs. The Qualcomm Universal Peripheral Engine (QUP) is a general
> purpose data path engine with input/output FIFOs and an embedded i2c
> mini-core. The driver supports FIFO mode (for low bandwidth applications)
> and block mode (interrupt generated for each block-size data transfer).
> The driver currently does not support DMA transfers.
>
> Shamelessly based on codeaurora version of the driver.
>
> Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
> [bjorn: updated to reflect i2c framework changes
> splited up qup_i2c_enable() in enable/disable
> don't overwrite ret value on error in xfer functions
> initilize core for each transfer
> remove explicit pinctrl selection
> use existing clock instead of setting new core clock]
> Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
> ---
<snip>
> +
> +static int qup_i2c_probe(struct platform_device *pdev)
> +{
> + struct device_node *node = pdev->dev.of_node;
> + struct qup_i2c_dev *qup;
> + struct resource *res;
> + u32 val, io_mode, hw_ver, size;
> + int ret, fs_div, hs_div;
> + int src_clk_freq;
> +
> + qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
> + if (!qup)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, qup);
> +
> + ret = of_alias_get_id(node, "i2c");
> + if (ret >= 0)
> + pdev->id = ret;
This is part of the i2c_add_adapter() and have to be dropped.
> +
> + qup->dev = &pdev->dev;
> +
> + qup->clk_freq = 100000;
> + if (!of_property_read_u32(node, "clock-frequency", &val))
> + qup->clk_freq = val;
> +
> + /* We support frequencies up to FAST Mode(400KHz) */
> + if (qup->clk_freq <= 0 || qup->clk_freq > 400000) {
> + dev_err(qup->dev, "clock frequency not supported %d\n",
> + qup->clk_freq);
> + return -EIO;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + qup->base = devm_ioremap_resource(qup->dev, res);
> + if (IS_ERR(qup->base))
> + return PTR_ERR(qup->base);
> +
> + qup->irq = platform_get_irq(pdev, 0);
> + if (qup->irq < 0) {
> + dev_err(qup->dev, "No IRQ defined\n");
> + return qup->irq;
> + }
> +
> + qup->clk = devm_clk_get(qup->dev, "core");
> + if (IS_ERR(qup->clk)) {
> + dev_err(qup->dev, "Could not get core clock\n");
> + return PTR_ERR(qup->clk);
> + }
> +
> + qup->pclk = devm_clk_get(qup->dev, "iface");
> + if (IS_ERR(qup->pclk)) {
> + dev_err(qup->dev, "Could not get iface clock\n");
> + return PTR_ERR(qup->pclk);
> + }
> +
> + init_completion(&qup->xfer);
> +
> + qup_i2c_enable_clocks(qup);
> +
> + /*
> + * Bootloaders might leave a pending interrupt on certain QUP's,
> + * so we reset the core before registering for interrupts.
> + */
> + writel(1, qup->base + QUP_SW_RESET);
> + ret = qup_i2c_poll_state(qup, 0, true);
> + if (ret)
> + goto fail;
> +
> + ret = devm_request_irq(qup->dev, qup->irq, qup_i2c_interrupt,
> + IRQF_TRIGGER_HIGH, "i2c_qup", qup);
> + if (ret) {
> + dev_err(qup->dev, "Request %d IRQ failed\n", qup->irq);
> + goto fail;
> + }
> + disable_irq(qup->irq);
> +
> + hw_ver = readl(qup->base + QUP_HW_VERSION);
> + dev_dbg(qup->dev, "%d Revision %x\n", pdev->id, hw_ver);
> +
> + src_clk_freq = clk_get_rate(qup->clk);
> + fs_div = ((src_clk_freq / qup->clk_freq) / 2) - 3;
> + hs_div = 3;
> + qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
> + qup->one_bit_t = (USEC_PER_SEC / qup->clk_freq) + 1;
> +
> + io_mode = readl(qup->base + QUP_IO_MODE);
> +
> + size = QUP_OUTPUT_BLOCK_SIZE(io_mode);
> + if (size)
> + qup->out_blk_sz = size * 16;
> + else
> + qup->out_blk_sz = 16;
> +
> + size = QUP_INPUT_BLOCK_SIZE(io_mode);
> + if (size)
> + qup->in_blk_sz = size * 16;
> + else
> + qup->in_blk_sz = 16;
> +
> + qup->xfer_time = msecs_to_jiffies(qup->out_fifo_sz);
> +
> + /*
> + * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
> + * associated with each byte written/received
> + */
> + qup->out_blk_sz /= 2;
> + qup->in_blk_sz /= 2;
> +
> + size = QUP_OUTPUT_FIFO_SIZE(io_mode);
> + qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
> +
> + size = QUP_INPUT_FIFO_SIZE(io_mode);
> + qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
> +
> + /*
> + * Wait for FIFO number of bytes to be absolutely sure
> + * that I2C write state machine is not idle. Each byte
> + * takes 9 clock cycles. (8 bits + 1 ack)
> + */
> + qup->wait_idle = qup->one_bit_t * 9;
> + qup->wait_idle *= qup->out_fifo_sz;
> +
> + dev_info(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
> + qup->in_blk_sz, qup->in_fifo_sz,
> + qup->out_blk_sz, qup->out_fifo_sz);
This could be lowered to dbg, I think.
> +
> + i2c_set_adapdata(&qup->adap, qup);
> + qup->adap.algo = &qup_i2c_algo;
> + qup->adap.nr = pdev->id;
> + qup->adap.dev.parent = qup->dev;
> + qup->adap.dev.of_node = pdev->dev.of_node;
> + strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
> +
> + ret = i2c_add_numbered_adapter(&qup->adap);
> + if (!ret) {
> + pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC);
> + pm_runtime_use_autosuspend(qup->dev);
> + pm_runtime_enable(qup->dev);
> + return 0;
> + }
> +fail:
> + qup_i2c_disable_clocks(qup);
> + return ret;
> +}
> +
Thanks,
Ivan
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller
[not found] ` <1389659437-16406-3-git-send-email-bjorn.andersson@sonymobile.com>
2014-01-14 13:03 ` [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller Ivan T. Ivanov
@ 2014-01-15 16:46 ` Stephen Boyd
2014-01-16 13:37 ` Ivan T. Ivanov
2014-01-17 0:18 ` Bjorn Andersson
1 sibling, 2 replies; 9+ messages in thread
From: Stephen Boyd @ 2014-01-15 16:46 UTC (permalink / raw)
To: linux-arm-kernel
On 01/13, Bjorn Andersson wrote:
> +/*
> + * QUP driver for Qualcomm MSM platforms
> + *
> + */
This comment seems redundant, we know what file we're looking at.
> +
> +struct qup_i2c_dev {
> + struct device *dev;
> + void __iomem *base;
> + struct pinctrl *pctrl;
This is unused.
> + int irq;
> + struct clk *clk;
> + struct clk *pclk;
> + struct i2c_adapter adap;
> +
> + int clk_freq;
This is only ever used in probe, so why do we need to store it
away?
> + int clk_ctl;
> + int one_bit_t;
> + int out_fifo_sz;
> + int in_fifo_sz;
> + int out_blk_sz;
> + int in_blk_sz;
> + unsigned long xfer_time;
> + unsigned long wait_idle;
> +
> + struct i2c_msg *msg;
> + /* Current possion in user message buffer */
s/possion/position/?
> + int pos;
> + /* Keep number of bytes left to be transmitted */
> + int cnt;
> + /* I2C protocol errors */
> + u32 bus_err;
> + /* QUP core errors */
> + u32 qup_err;
> + /*
> + * maximum bytes that could be send (per iterration). could be
s/iterration/iteration/?
> + * equal of fifo size or block size (in block mode)
> + */
> + int chunk_sz;
> + struct completion xfer;
> +};
> +
> +static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
> +{
> + struct qup_i2c_dev *qup = dev;
> + u32 bus_err;
> + u32 qup_err;
> + u32 opflags;
> +
[...]
> +
> + if (opflags & QUP_OUT_SVC_FLAG)
> + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> +
> + if (!(qup->msg->flags == I2C_M_RD))
Should this be?
if (!(qup->msg->flags & I2C_M_RD))
Otherwise it should be
if (qup->msg->flags != I2C_M_RD)
> + return IRQ_HANDLED;
> +
> + if ((opflags & QUP_MX_INPUT_DONE) || (opflags & QUP_IN_SVC_FLAG))
> + writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> +
> +done:
> + qup->qup_err = qup_err;
> + qup->bus_err = bus_err;
> + complete(&qup->xfer);
> + return IRQ_HANDLED;
> +}
> +
> +static int
> +qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state, bool only_valid)
> +{
> + int retries = 0;
> + u32 state;
> +
> + do {
> + state = readl(qup->base + QUP_STATE);
> +
> + /*
> + * If only valid bit needs to be checked, requested state is
> + * 'don't care'
> + */
It looks like req_state == 0 means only_valid == true. Can we
drop the only_valid argument to this function?
> + if (state & QUP_STATE_VALID) {
> + if (only_valid)
> + return 0;
> + if ((req_state & QUP_I2C_MAST_GEN)
> + && (state & QUP_I2C_MAST_GEN))
> + return 0;
> + if ((state & QUP_STATE_MASK) == req_state)
> + return 0;
> + }
> +
> + if (retries++ == 1000)
> + udelay(100);
> +
> + } while (retries != 2000);
Please makes #defines for 1000 and 2000.
> +
> + return -ETIMEDOUT;
> +}
> +
[...]
> +static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +{
> + u32 addr = msg->addr << 1;
> + u32 val, qup_tag;
> + int idx, entries;
> +
> + if (qup->pos == 0) {
> + val = QUP_OUT_START | addr;
> + } else {
> + /*
> + * Avoid setup time issue by adding 1 NOP when number of bytes
> + * are more than FIFO/BLOCK size. setup time issue can't appear
> + * otherwise since next byte to be written will always be ready
> + */
> + val = (QUP_OUT_NOP | 1);
> + }
> +
> + entries = qup->cnt + 1;
> +
> + if (entries > qup->chunk_sz)
> + entries = qup->chunk_sz;
> +
> + qup_tag = QUP_OUT_DATA;
> +
> + /* Reserve one entry for STOP */
> + for (idx = 1; idx < (entries - 1); idx++, qup->pos++) {
Unnecessary () here around entries.
> +
> + if (idx & 1) {
> + val |= (qup_tag | msg->buf[qup->pos]) << QUP_MSW_SHIFT;
> + writel(val, qup->base + QUP_OUT_FIFO_BASE);
> + } else {
> + val = qup_tag | msg->buf[qup->pos];
> + }
[...]
> +
> +#ifdef CONFIG_PM
This ifdef is probably wrong considering that you can disable
CONFIG_PM_RUNTIME without disabling CONFIG_PM and then these
runtime PM functions would be unused.
> +static int qup_i2c_pm_suspend_runtime(struct device *device)
> +{
> + struct qup_i2c_dev *qup = dev_get_drvdata(device);
> +
> + dev_dbg(device, "pm_runtime: suspending...\n");
> + qup_i2c_disable_clocks(qup);
> + return 0;
> +}
> +
> +static int qup_i2c_pm_resume_runtime(struct device *device)
> +{
> + struct qup_i2c_dev *qup = dev_get_drvdata(device);
> +
> + dev_dbg(device, "pm_runtime: resuming...\n");
> + qup_i2c_enable_clocks(qup);
> + return 0;
> +}
> +
> +static int qup_i2c_suspend(struct device *device)
> +{
> + dev_dbg(device, "system suspend");
> + qup_i2c_pm_suspend_runtime(device);
> + return 0;
> +}
> +
> +static int qup_i2c_resume(struct device *device)
> +{
> + dev_dbg(device, "system resume");
> + qup_i2c_pm_resume_runtime(device);
> + pm_runtime_mark_last_busy(device);
> + pm_request_autosuspend(device);
> + return 0;
> +}
> +#endif /* CONFIG_PM */
> +
> +static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(
> + qup_i2c_suspend,
> + qup_i2c_resume)
> + SET_RUNTIME_PM_OPS(
> + qup_i2c_pm_suspend_runtime,
> + qup_i2c_pm_resume_runtime,
> + NULL)
> +};
> +
> +static struct of_device_id qup_i2c_dt_match[] = {
const?
> + {.compatible = "qcom,i2c-qup"},
> + {}
> +};
MODULE_DEVICE_TABLE(of, qup_i2c_dt_match)?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller
2014-01-15 16:46 ` Stephen Boyd
@ 2014-01-16 13:37 ` Ivan T. Ivanov
2014-01-17 0:18 ` Bjorn Andersson
1 sibling, 0 replies; 9+ messages in thread
From: Ivan T. Ivanov @ 2014-01-16 13:37 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On Wed, 2014-01-15 at 08:46 -0800, Stephen Boyd wrote:
> On 01/13, Bjorn Andersson wrote:
> > +/*
> > + * QUP driver for Qualcomm MSM platforms
> > + *
> > + */
>
> This comment seems redundant, we know what file we're looking at.
>
> > +
> > +struct qup_i2c_dev {
> > + struct device *dev;
> > + void __iomem *base;
> > + struct pinctrl *pctrl;
>
> This is unused.
>
> > + int irq;
> > + struct clk *clk;
> > + struct clk *pclk;
> > + struct i2c_adapter adap;
> > +
> > + int clk_freq;
>
> This is only ever used in probe, so why do we need to store it
> away?
>
> > + int clk_ctl;
> > + int one_bit_t;
> > + int out_fifo_sz;
> > + int in_fifo_sz;
> > + int out_blk_sz;
> > + int in_blk_sz;
> > + unsigned long xfer_time;
> > + unsigned long wait_idle;
> > +
> > + struct i2c_msg *msg;
> > + /* Current possion in user message buffer */
>
> s/possion/position/?
>
> > + int pos;
> > + /* Keep number of bytes left to be transmitted */
> > + int cnt;
> > + /* I2C protocol errors */
> > + u32 bus_err;
> > + /* QUP core errors */
> > + u32 qup_err;
> > + /*
> > + * maximum bytes that could be send (per iterration). could be
>
> s/iterration/iteration/?
>
> > + * equal of fifo size or block size (in block mode)
> > + */
> > + int chunk_sz;
> > + struct completion xfer;
> > +};
> > +
> > +static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
> > +{
> > + struct qup_i2c_dev *qup = dev;
> > + u32 bus_err;
> > + u32 qup_err;
> > + u32 opflags;
> > +
> [...]
> > +
> > + if (opflags & QUP_OUT_SVC_FLAG)
> > + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> > +
> > + if (!(qup->msg->flags == I2C_M_RD))
>
> Should this be?
>
> if (!(qup->msg->flags & I2C_M_RD))
>
> Otherwise it should be
>
> if (qup->msg->flags != I2C_M_RD)
>
This check is actually broken. Intention was that if this is read
transaction and there is no QUP_MX_INPUT_DONE or QUP_IN_SVC_FLAG
to exit without wakeup transfer thread. As is it now it will never
complete write transactions.
Regards,
Ivan
> > + return IRQ_HANDLED;
> > +
> > + if ((opflags & QUP_MX_INPUT_DONE) || (opflags & QUP_IN_SVC_FLAG))
> > + writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> > +
> > +done:
> > + qup->qup_err = qup_err;
> > + qup->bus_err = bus_err;
> > + complete(&qup->xfer);
> > + return IRQ_HANDLED;
> > +}
> > +
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/2] i2c: qup: Add device tree bindings information
2014-01-14 8:57 ` [PATCH v2 1/2] i2c: qup: Add device tree bindings information Ivan T. Ivanov
@ 2014-01-16 23:20 ` Bjorn Andersson
2014-01-17 7:40 ` Ivan T. Ivanov
0 siblings, 1 reply; 9+ messages in thread
From: Bjorn Andersson @ 2014-01-16 23:20 UTC (permalink / raw)
To: linux-arm-kernel
On Tue 14 Jan 00:57 PST 2014, Ivan T. Ivanov wrote:
>
> Thanks Bjorn,
>
> I have prepared second version, but never send it out :-).
> One thing suggested by Mark was missed in this version.
Yeah, Mattew told me you we're assigned to other things and asked me to send
out an update as I had gotten it to work on our boards.
I did modify the wording of most of these to match how it is written in the
other Qualcomm definitions.
@Mark, would you rather have me change this to your suggested wording?
>
>
> On Mon, 2014-01-13 at 16:30 -0800, Bjorn Andersson wrote:
> > From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
> >
[snip]
> > + - clocks: Should contain the core clock and the AHB clock.
>
> + - clocks: a list of phandle + clock-specifier pairs for each entry in
> + clock-names
>
This is in line with how it's written in other drivers, so if the DT
maintainers doesn't disagree I would like to keep phandles out of the
description. This specific line is a verbatime copy of the msm_serial
documentation (same block, different mode)...
> > + - clock-names: Should be "core" for the core clock and "iface" for the
> > + AHB clock.
> > +
> > + - #address-cells: Should be <1> Address cells for i2c device address
> > + - #size-cells: Should be <0> as i2c addresses have no size component
> > +
> > +Optional properties:
> > + - clock-frequency: Should specify the desired i2c bus clock frequency in Hz,
> > + default is 100kHz if omitted.
> > +
> > +Child nodes should conform to i2c bus binding.
> > +
> > +Example:
> > +
> > + i2c2: i2c at f9924000 {
> > + compatible = "qcom,i2c-qup";
> > + reg = <0xf9924000 0x1000>;
> > + interrupts = <0 96 0>;
> > +
> > + clocks = <&gcc_blsp1_qup2_i2c_apps_clk>, <&gcc_blsp1_ahb_clk>;
>
> In the light of the latest patches from Stephen, this could be
>
> + clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
Yes, that's exactly what I have in my dts. However as this is just an example
I didn't feel it was worth tainting the documentation with all those capital
letters ;)
So unless DT maintainers disagree I would like to just keep it as an example.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller
2014-01-15 16:46 ` Stephen Boyd
2014-01-16 13:37 ` Ivan T. Ivanov
@ 2014-01-17 0:18 ` Bjorn Andersson
2014-01-17 0:33 ` Stephen Boyd
1 sibling, 1 reply; 9+ messages in thread
From: Bjorn Andersson @ 2014-01-17 0:18 UTC (permalink / raw)
To: linux-arm-kernel
On Wed 15 Jan 08:46 PST 2014, Stephen Boyd wrote:
> On 01/13, Bjorn Andersson wrote:
> > +/*
> > + * QUP driver for Qualcomm MSM platforms
> > + *
> > + */
>
> This comment seems redundant, we know what file we're looking at.
>
Indeed.
> > +
> > +struct qup_i2c_dev {
> > + struct device *dev;
> > + void __iomem *base;
> > + struct pinctrl *pctrl;
>
> This is unused.
>
Removed.
> > + int irq;
> > + struct clk *clk;
> > + struct clk *pclk;
> > + struct i2c_adapter adap;
> > +
> > + int clk_freq;
>
> This is only ever used in probe, so why do we need to store it
> away?
>
Moved to probe()
> > + int clk_ctl;
> > + int one_bit_t;
> > + int out_fifo_sz;
> > + int in_fifo_sz;
> > + int out_blk_sz;
> > + int in_blk_sz;
> > + unsigned long xfer_time;
> > + unsigned long wait_idle;
> > +
> > + struct i2c_msg *msg;
> > + /* Current possion in user message buffer */
>
> s/possion/position/?
>
Thanks.
> > + int pos;
> > + /* Keep number of bytes left to be transmitted */
> > + int cnt;
> > + /* I2C protocol errors */
> > + u32 bus_err;
> > + /* QUP core errors */
> > + u32 qup_err;
> > + /*
> > + * maximum bytes that could be send (per iterration). could be
>
> s/iterration/iteration/?
>
Thanks
> > + * equal of fifo size or block size (in block mode)
> > + */
> > + int chunk_sz;
> > + struct completion xfer;
> > +};
> > +
> > +static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
> > +{
> > + struct qup_i2c_dev *qup = dev;
> > + u32 bus_err;
> > + u32 qup_err;
> > + u32 opflags;
> > +
> [...]
> > +
> > + if (opflags & QUP_OUT_SVC_FLAG)
> > + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> > +
> > + if (!(qup->msg->flags == I2C_M_RD))
>
> Should this be?
>
> if (!(qup->msg->flags & I2C_M_RD))
>
> Otherwise it should be
>
> if (qup->msg->flags != I2C_M_RD)
>
In the codeaurora implementation this seem to be:
if (qup->msg->flags == I2C_M_RD) {
if ((opflags & QUP_MX_INPUT_DONE) || (opflags & QUP_IN_SVC_FLAG))
writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
else
return IRQ_HANDLED;
}
So, do not complete the xfer unless there's something for us.
I'll verify this and update the next version.
Thanks.
> > + return IRQ_HANDLED;
> > +
> > + if ((opflags & QUP_MX_INPUT_DONE) || (opflags & QUP_IN_SVC_FLAG))
> > + writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> > +
> > +done:
> > + qup->qup_err = qup_err;
> > + qup->bus_err = bus_err;
> > + complete(&qup->xfer);
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int
> > +qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state, bool only_valid)
> > +{
> > + int retries = 0;
> > + u32 state;
> > +
> > + do {
> > + state = readl(qup->base + QUP_STATE);
> > +
> > + /*
> > + * If only valid bit needs to be checked, requested state is
> > + * 'don't care'
> > + */
>
> It looks like req_state == 0 means only_valid == true. Can we
> drop the only_valid argument to this function?
>
In all cases but the reset in the beginning of qup_i2c_xfer, so it seems that
it has to stay.
> > + if (state & QUP_STATE_VALID) {
> > + if (only_valid)
> > + return 0;
> > + if ((req_state & QUP_I2C_MAST_GEN)
> > + && (state & QUP_I2C_MAST_GEN))
> > + return 0;
> > + if ((state & QUP_STATE_MASK) == req_state)
> > + return 0;
> > + }
> > +
> > + if (retries++ == 1000)
> > + udelay(100);
> > +
> > + } while (retries != 2000);
>
> Please makes #defines for 1000 and 2000.
>
This retry loop looks completely arbitrary to me now that you say it. I'll
revise this.
> > +
> > + return -ETIMEDOUT;
> > +}
> > +
> [...]
> > +static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> > +{
> > + u32 addr = msg->addr << 1;
> > + u32 val, qup_tag;
> > + int idx, entries;
> > +
> > + if (qup->pos == 0) {
> > + val = QUP_OUT_START | addr;
> > + } else {
> > + /*
> > + * Avoid setup time issue by adding 1 NOP when number of bytes
> > + * are more than FIFO/BLOCK size. setup time issue can't appear
> > + * otherwise since next byte to be written will always be ready
> > + */
> > + val = (QUP_OUT_NOP | 1);
> > + }
> > +
> > + entries = qup->cnt + 1;
> > +
> > + if (entries > qup->chunk_sz)
> > + entries = qup->chunk_sz;
> > +
> > + qup_tag = QUP_OUT_DATA;
> > +
> > + /* Reserve one entry for STOP */
> > + for (idx = 1; idx < (entries - 1); idx++, qup->pos++) {
>
> Unnecessary () here around entries.
>
Sure.
> > +
> > + if (idx & 1) {
> > + val |= (qup_tag | msg->buf[qup->pos]) << QUP_MSW_SHIFT;
> > + writel(val, qup->base + QUP_OUT_FIFO_BASE);
> > + } else {
> > + val = qup_tag | msg->buf[qup->pos];
> > + }
> [...]
> > +
> > +#ifdef CONFIG_PM
>
> This ifdef is probably wrong considering that you can disable
> CONFIG_PM_RUNTIME without disabling CONFIG_PM and then these
> runtime PM functions would be unused.
>
Will fix.
> > +static int qup_i2c_pm_suspend_runtime(struct device *device)
> > +{
> > + struct qup_i2c_dev *qup = dev_get_drvdata(device);
> > +
> > + dev_dbg(device, "pm_runtime: suspending...\n");
> > + qup_i2c_disable_clocks(qup);
> > + return 0;
> > +}
> > +
> > +static int qup_i2c_pm_resume_runtime(struct device *device)
> > +{
> > + struct qup_i2c_dev *qup = dev_get_drvdata(device);
> > +
> > + dev_dbg(device, "pm_runtime: resuming...\n");
> > + qup_i2c_enable_clocks(qup);
> > + return 0;
> > +}
> > +
> > +static int qup_i2c_suspend(struct device *device)
> > +{
> > + dev_dbg(device, "system suspend");
> > + qup_i2c_pm_suspend_runtime(device);
> > + return 0;
> > +}
> > +
> > +static int qup_i2c_resume(struct device *device)
> > +{
> > + dev_dbg(device, "system resume");
> > + qup_i2c_pm_resume_runtime(device);
> > + pm_runtime_mark_last_busy(device);
> > + pm_request_autosuspend(device);
> > + return 0;
> > +}
> > +#endif /* CONFIG_PM */
> > +
> > +static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
> > + SET_SYSTEM_SLEEP_PM_OPS(
> > + qup_i2c_suspend,
> > + qup_i2c_resume)
> > + SET_RUNTIME_PM_OPS(
> > + qup_i2c_pm_suspend_runtime,
> > + qup_i2c_pm_resume_runtime,
> > + NULL)
> > +};
> > +
> > +static struct of_device_id qup_i2c_dt_match[] = {
>
> const?
>
Sure
> > + {.compatible = "qcom,i2c-qup"},
> > + {}
> > +};
>
> MODULE_DEVICE_TABLE(of, qup_i2c_dt_match)?
>
OK
Thanks Stephen!
// Bjorn
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller
2014-01-17 0:18 ` Bjorn Andersson
@ 2014-01-17 0:33 ` Stephen Boyd
2014-01-17 22:19 ` Bjorn Andersson
0 siblings, 1 reply; 9+ messages in thread
From: Stephen Boyd @ 2014-01-17 0:33 UTC (permalink / raw)
To: linux-arm-kernel
On 01/16, Bjorn Andersson wrote:
> On Wed 15 Jan 08:46 PST 2014, Stephen Boyd wrote:
>
> > On 01/13, Bjorn Andersson wrote:
> > > +
> > > +static int
> > > +qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state, bool only_valid)
> > > +{
> > > + int retries = 0;
> > > + u32 state;
> > > +
> > > + do {
> > > + state = readl(qup->base + QUP_STATE);
> > > +
> > > + /*
> > > + * If only valid bit needs to be checked, requested state is
> > > + * 'don't care'
> > > + */
> >
> > It looks like req_state == 0 means only_valid == true. Can we
> > drop the only_valid argument to this function?
> >
>
> In all cases but the reset in the beginning of qup_i2c_xfer, so it seems that
> it has to stay.
Oh that's because QUP_RESET_STATE is equal to 0? It looks like
bits 0 and 1 are the state field and bit 2 is a flag indicating
that bits 0 and 1 are valid. Why not OR in the QUP_STATE_VALID
flag into the macros that are passed to this function? Then the
logic would simply be looping looking for a match of the
req_state (which is really a mask now).
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/2] i2c: qup: Add device tree bindings information
2014-01-16 23:20 ` Bjorn Andersson
@ 2014-01-17 7:40 ` Ivan T. Ivanov
0 siblings, 0 replies; 9+ messages in thread
From: Ivan T. Ivanov @ 2014-01-17 7:40 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On Thu, 2014-01-16 at 15:20 -0800, Bjorn Andersson wrote:
> On Tue 14 Jan 00:57 PST 2014, Ivan T. Ivanov wrote:
>
> >
> > Thanks Bjorn,
> >
> > I have prepared second version, but never send it out :-).
> > One thing suggested by Mark was missed in this version.
>
> Yeah, Mattew told me you we're assigned to other things and asked me to send
> out an update as I had gotten it to work on our boards.
>
> I did modify the wording of most of these to match how it is written in the
> other Qualcomm definitions.
>
> @Mark, would you rather have me change this to your suggested wording?
>
> >
> >
> > On Mon, 2014-01-13 at 16:30 -0800, Bjorn Andersson wrote:
> > > From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
> > >
> [snip]
> > > + - clocks: Should contain the core clock and the AHB clock.
> >
> > + - clocks: a list of phandle + clock-specifier pairs for each entry in
> > + clock-names
> >
>
> This is in line with how it's written in other drivers, so if the DT
> maintainers doesn't disagree I would like to keep phandles out of the
> description. This specific line is a verbatime copy of the msm_serial
> documentation (same block, different mode)...
>
> > > + - clock-names: Should be "core" for the core clock and "iface" for the
> > > + AHB clock.
> > > +
> > > + - #address-cells: Should be <1> Address cells for i2c device address
> > > + - #size-cells: Should be <0> as i2c addresses have no size component
> > > +
> > > +Optional properties:
> > > + - clock-frequency: Should specify the desired i2c bus clock frequency in Hz,
> > > + default is 100kHz if omitted.
> > > +
> > > +Child nodes should conform to i2c bus binding.
> > > +
> > > +Example:
> > > +
> > > + i2c2: i2c at f9924000 {
> > > + compatible = "qcom,i2c-qup";
> > > + reg = <0xf9924000 0x1000>;
> > > + interrupts = <0 96 0>;
> > > +
> > > + clocks = <&gcc_blsp1_qup2_i2c_apps_clk>, <&gcc_blsp1_ahb_clk>;
> >
> > In the light of the latest patches from Stephen, this could be
> >
> > + clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
>
> Yes, that's exactly what I have in my dts. However as this is just an example
> I didn't feel it was worth tainting the documentation with all those capital
> letters ;)
> So unless DT maintainers disagree I would like to just keep it as an example.
Until, we get some meaningful board DTS files for Qualcomm platforms, it
is easy for people which will like to test or use drivers to just copy
and paste these definitions.
Regards,
Ivan
>
> Regards,
> Bjorn
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller
2014-01-17 0:33 ` Stephen Boyd
@ 2014-01-17 22:19 ` Bjorn Andersson
0 siblings, 0 replies; 9+ messages in thread
From: Bjorn Andersson @ 2014-01-17 22:19 UTC (permalink / raw)
To: linux-arm-kernel
On Thu 16 Jan 16:33 PST 2014, Stephen Boyd wrote:
> On 01/16, Bjorn Andersson wrote:
> > On Wed 15 Jan 08:46 PST 2014, Stephen Boyd wrote:
> >
> > > On 01/13, Bjorn Andersson wrote:
> > > > +
> > > > +static int
> > > > +qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state, bool only_valid)
> > > > +{
> > > > + int retries = 0;
> > > > + u32 state;
> > > > +
> > > > + do {
> > > > + state = readl(qup->base + QUP_STATE);
> > > > +
> > > > + /*
> > > > + * If only valid bit needs to be checked, requested state is
> > > > + * 'don't care'
> > > > + */
> > >
> > > It looks like req_state == 0 means only_valid == true. Can we
> > > drop the only_valid argument to this function?
> > >
> >
> > In all cases but the reset in the beginning of qup_i2c_xfer, so it seems that
> > it has to stay.
>
> Oh that's because QUP_RESET_STATE is equal to 0? It looks like
> bits 0 and 1 are the state field and bit 2 is a flag indicating
> that bits 0 and 1 are valid. Why not OR in the QUP_STATE_VALID
> flag into the macros that are passed to this function? Then the
> logic would simply be looping looking for a match of the
> req_state (which is really a mask now).
While it's true that req_state == 0 means only_valid, it is not true that
only_valid means req_state == 0. So there would be no way to differentiate
between "valid and reset" and "valid and don't care about run/pause/reset".
So I could move the logic around, but I don't see how we could reduce the
number of parameters to the function.
// Bjorn
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2014-01-17 22:19 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1389659437-16406-1-git-send-email-bjorn.andersson@sonymobile.com>
[not found] ` <1389659437-16406-2-git-send-email-bjorn.andersson@sonymobile.com>
2014-01-14 8:57 ` [PATCH v2 1/2] i2c: qup: Add device tree bindings information Ivan T. Ivanov
2014-01-16 23:20 ` Bjorn Andersson
2014-01-17 7:40 ` Ivan T. Ivanov
[not found] ` <1389659437-16406-3-git-send-email-bjorn.andersson@sonymobile.com>
2014-01-14 13:03 ` [PATCH v2 2/2] i2c: New bus driver for the QUP I2C controller Ivan T. Ivanov
2014-01-15 16:46 ` Stephen Boyd
2014-01-16 13:37 ` Ivan T. Ivanov
2014-01-17 0:18 ` Bjorn Andersson
2014-01-17 0:33 ` Stephen Boyd
2014-01-17 22:19 ` Bjorn Andersson
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).