From: "Ivan T. Ivanov" <iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
To: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Grant Likely
<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
linux-spi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Alok Chauhan <alokc-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>,
Gilad Avidov <gavidov-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>,
Kiran Gunda <kgunda-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>,
Sagar Dharia <sdharia-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Subject: Re: [PATCH 2/2] spi: Add Qualcomm QUP SPI controller support
Date: Mon, 10 Feb 2014 18:29:26 +0200 [thread overview]
Message-ID: <1392049766.2853.43.camel@iivanov-dev> (raw)
In-Reply-To: <20140207171202.GD1757-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
Hi,
On Fri, 2014-02-07 at 17:12 +0000, Mark Brown wrote:
> On Thu, Feb 06, 2014 at 06:57:48PM +0200, Ivan T. Ivanov wrote:
>
> This looks mostly good, there's a few odd things and missing use of
> framework features.
>
> > Qualcomm Universal Peripheral (QUP) core is an AHB slave that
> > provides a common data path (an output FIFO and an input FIFO)
> > for serial peripheral interface (SPI) mini-core. SPI in master mode
> > support up to 50MHz, up to four chip selects, and a programmable
> > data path from 4 bits to 32 bits; MODE0..3 protocols
>
> The grammar in this and the Kconfig text is a bit garbled, might want to
> give it a once over (support -> supports for example).
Ok
>
> > +static void spi_qup_deassert_cs(struct spi_qup *controller,
> > + struct spi_qup_device *chip)
> > +{
>
>
> > + if (chip->mode & SPI_CS_HIGH)
> > + iocontol &= ~mask;
> > + else
> > + iocontol |= mask;
>
> Implement a set_cs() operation and let the core worry about all this
> for you as well as saving two implementations.
Nice. Will us it.
>
> > + word = 0;
> > + for (idx = 0; idx < controller->bytes_per_word &&
> > + controller->tx_bytes < xfer->len; idx++,
> > + controller->tx_bytes++) {
> > +
> > + if (!tx_buf)
> > + continue;
>
> Do you need to set the _MUST_TX flag?
>
> > + qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
> > + spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
> > + opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
> > +
> > + writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
> > + writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
> > + writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
> > +
> > + if (!xfer)
> > + return IRQ_HANDLED;
>
> Are you sure? It seems wrong to just ignore interrupts, some comments
> would help explain why.
Of course this should never happen. This was left from initial stage
of the implementation.
>
> > +static int spi_qup_transfer_do(struct spi_qup *controller,
> > + struct spi_qup_device *chip,
> > + struct spi_transfer *xfer)
>
> This looks like a transfer_one() function, please use the framework
> features where you can.
Sure, will do. Somehow I have missed this.
>
> > + if (controller->speed_hz != chip->speed_hz) {
> > + ret = clk_set_rate(controller->cclk, chip->speed_hz);
> > + if (ret) {
> > + dev_err(controller->dev, "fail to set frequency %d",
> > + chip->speed_hz);
> > + return -EIO;
> > + }
> > + }
>
> Is calling into the clock framework really so expensive that we need to
> avoid doing it?
Probably not. But why to call it if the frequency is the same.
> You also shouldn't be interacting with the hardware in
> setup().
This is internal hw-setup, not master::setup() or I am
missing something?
>
> > + if (chip->bits_per_word <= 8)
> > + controller->bytes_per_word = 1;
> > + else if (chip->bits_per_word <= 16)
> > + controller->bytes_per_word = 2;
> > + else
> > + controller->bytes_per_word = 4;
>
> This looks like a switch statement, and looking at the above it's not
> clear that the device actually supports anything other than whole bytes.
> I'm not sure what that would mean from an API point of view.
SPI API didn't validate struct spi_transfer::len field.
The whole sniped looks like this:
chip->bits_per_word = spi->bits_per_word;
if (xfer->bits_per_word)
chip->bits_per_word = xfer->bits_per_word;
if (chip->bits_per_word <= 8)
controller->bytes_per_word = 1;
else if (chip->bits_per_word <= 16)
controller->bytes_per_word = 2;
else
controller->bytes_per_word = 4;
if (controller->bytes_per_word > xfer->len ||
xfer->len % controller->bytes_per_word != 0){
/* No partial transfers */
dev_err(controller->dev, "invalid len %d for %d bits\n",
xfer->len, chip->bits_per_word);
return -EIO;
}
n_words = xfer->len / controller->bytes_per_word;
'bytes_per_word' have to be power of 2. This is my understanding of
struct spi_transfer description. So I am discarding all transfers with
'len' non multiple of word size.
>
> > +static int spi_qup_transfer_one(struct spi_master *master,
> > + struct spi_message *msg)
> > +{
>
> This entire function can be removed, the core can do it for you.
Sure, will use it.
>
> > + if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
> > + max_freq = 19200000;
> > +
> > + if (!max_freq) {
> > + dev_err(dev, "invalid clock frequency %d\n", max_freq);
> > + return -ENXIO;
> > + }
> > +
> > + ret = clk_set_rate(cclk, max_freq);
> > + if (ret)
> > + dev_warn(dev, "fail to set SPI frequency %d\n", max_freq);
>
> You set the clock rate per transfer so why bother setting it here,
Only if differs from the current one.
> perhaps we support the rate the devices request but not this maximum
> rate?
Thats why it is just a warning. I will see how to handle this better.
>
> > + master->num_chipselect = SPI_NUM_CHIPSELECTS;
> > + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
>
> Are you *sure* the device supports anything other than whole bytes?
Yep. I see them on the scope.
>
> > + ret = devm_spi_register_master(dev, master);
> > + if (!ret) {
> > + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
> > + pm_runtime_use_autosuspend(dev);
> > + pm_runtime_set_active(dev);
> > + pm_runtime_enable(dev);
> > + return ret;
> > + }
>
> This is really unclearly written, the success case looks like error
> handling.
I suppose that if use a goto, I will have to do it consistently.
Will rework it.
>
> > +#ifdef CONFIG_PM_RUNTIME
> > +static int spi_qup_pm_suspend_runtime(struct device *device)
> > +{
> > + struct spi_master *master = dev_get_drvdata(device);
> > + struct spi_qup *controller = spi_master_get_devdata(master);
> > +
> > + disable_irq(controller->irq);
>
> Why do you need to disable the interrupt? Will the hardware generate
> spurious interrupts, if so some documentation is in order.
I don't know. Just extra protection? I will have t o find how to
test this.
>
> > +static int spi_qup_pm_resume_runtime(struct device *device)
> > +{
> > + struct spi_master *master = dev_get_drvdata(device);
> > + struct spi_qup *controller = spi_master_get_devdata(master);
> > +
> > + clk_prepare_enable(controller->cclk);
> > + clk_prepare_enable(controller->iclk);
> > + enable_irq(controller->irq);
>
> No error checking here...
Will fix.
Thanks,
Ivan
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
WARNING: multiple messages have this Message-ID (diff)
From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
To: Mark Brown <broonie@kernel.org>
Cc: Grant Likely <grant.likely@linaro.org>,
Rob Herring <robh+dt@kernel.org>,
linux-spi@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
Alok Chauhan <alokc@codeaurora.org>,
Gilad Avidov <gavidov@codeaurora.org>,
Kiran Gunda <kgunda@codeaurora.org>,
Sagar Dharia <sdharia@codeaurora.org>
Subject: Re: [PATCH 2/2] spi: Add Qualcomm QUP SPI controller support
Date: Mon, 10 Feb 2014 18:29:26 +0200 [thread overview]
Message-ID: <1392049766.2853.43.camel@iivanov-dev> (raw)
In-Reply-To: <20140207171202.GD1757@sirena.org.uk>
Hi,
On Fri, 2014-02-07 at 17:12 +0000, Mark Brown wrote:
> On Thu, Feb 06, 2014 at 06:57:48PM +0200, Ivan T. Ivanov wrote:
>
> This looks mostly good, there's a few odd things and missing use of
> framework features.
>
> > Qualcomm Universal Peripheral (QUP) core is an AHB slave that
> > provides a common data path (an output FIFO and an input FIFO)
> > for serial peripheral interface (SPI) mini-core. SPI in master mode
> > support up to 50MHz, up to four chip selects, and a programmable
> > data path from 4 bits to 32 bits; MODE0..3 protocols
>
> The grammar in this and the Kconfig text is a bit garbled, might want to
> give it a once over (support -> supports for example).
Ok
>
> > +static void spi_qup_deassert_cs(struct spi_qup *controller,
> > + struct spi_qup_device *chip)
> > +{
>
>
> > + if (chip->mode & SPI_CS_HIGH)
> > + iocontol &= ~mask;
> > + else
> > + iocontol |= mask;
>
> Implement a set_cs() operation and let the core worry about all this
> for you as well as saving two implementations.
Nice. Will us it.
>
> > + word = 0;
> > + for (idx = 0; idx < controller->bytes_per_word &&
> > + controller->tx_bytes < xfer->len; idx++,
> > + controller->tx_bytes++) {
> > +
> > + if (!tx_buf)
> > + continue;
>
> Do you need to set the _MUST_TX flag?
>
> > + qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
> > + spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
> > + opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
> > +
> > + writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
> > + writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
> > + writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
> > +
> > + if (!xfer)
> > + return IRQ_HANDLED;
>
> Are you sure? It seems wrong to just ignore interrupts, some comments
> would help explain why.
Of course this should never happen. This was left from initial stage
of the implementation.
>
> > +static int spi_qup_transfer_do(struct spi_qup *controller,
> > + struct spi_qup_device *chip,
> > + struct spi_transfer *xfer)
>
> This looks like a transfer_one() function, please use the framework
> features where you can.
Sure, will do. Somehow I have missed this.
>
> > + if (controller->speed_hz != chip->speed_hz) {
> > + ret = clk_set_rate(controller->cclk, chip->speed_hz);
> > + if (ret) {
> > + dev_err(controller->dev, "fail to set frequency %d",
> > + chip->speed_hz);
> > + return -EIO;
> > + }
> > + }
>
> Is calling into the clock framework really so expensive that we need to
> avoid doing it?
Probably not. But why to call it if the frequency is the same.
> You also shouldn't be interacting with the hardware in
> setup().
This is internal hw-setup, not master::setup() or I am
missing something?
>
> > + if (chip->bits_per_word <= 8)
> > + controller->bytes_per_word = 1;
> > + else if (chip->bits_per_word <= 16)
> > + controller->bytes_per_word = 2;
> > + else
> > + controller->bytes_per_word = 4;
>
> This looks like a switch statement, and looking at the above it's not
> clear that the device actually supports anything other than whole bytes.
> I'm not sure what that would mean from an API point of view.
SPI API didn't validate struct spi_transfer::len field.
The whole sniped looks like this:
chip->bits_per_word = spi->bits_per_word;
if (xfer->bits_per_word)
chip->bits_per_word = xfer->bits_per_word;
if (chip->bits_per_word <= 8)
controller->bytes_per_word = 1;
else if (chip->bits_per_word <= 16)
controller->bytes_per_word = 2;
else
controller->bytes_per_word = 4;
if (controller->bytes_per_word > xfer->len ||
xfer->len % controller->bytes_per_word != 0){
/* No partial transfers */
dev_err(controller->dev, "invalid len %d for %d bits\n",
xfer->len, chip->bits_per_word);
return -EIO;
}
n_words = xfer->len / controller->bytes_per_word;
'bytes_per_word' have to be power of 2. This is my understanding of
struct spi_transfer description. So I am discarding all transfers with
'len' non multiple of word size.
>
> > +static int spi_qup_transfer_one(struct spi_master *master,
> > + struct spi_message *msg)
> > +{
>
> This entire function can be removed, the core can do it for you.
Sure, will use it.
>
> > + if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
> > + max_freq = 19200000;
> > +
> > + if (!max_freq) {
> > + dev_err(dev, "invalid clock frequency %d\n", max_freq);
> > + return -ENXIO;
> > + }
> > +
> > + ret = clk_set_rate(cclk, max_freq);
> > + if (ret)
> > + dev_warn(dev, "fail to set SPI frequency %d\n", max_freq);
>
> You set the clock rate per transfer so why bother setting it here,
Only if differs from the current one.
> perhaps we support the rate the devices request but not this maximum
> rate?
Thats why it is just a warning. I will see how to handle this better.
>
> > + master->num_chipselect = SPI_NUM_CHIPSELECTS;
> > + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
>
> Are you *sure* the device supports anything other than whole bytes?
Yep. I see them on the scope.
>
> > + ret = devm_spi_register_master(dev, master);
> > + if (!ret) {
> > + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
> > + pm_runtime_use_autosuspend(dev);
> > + pm_runtime_set_active(dev);
> > + pm_runtime_enable(dev);
> > + return ret;
> > + }
>
> This is really unclearly written, the success case looks like error
> handling.
I suppose that if use a goto, I will have to do it consistently.
Will rework it.
>
> > +#ifdef CONFIG_PM_RUNTIME
> > +static int spi_qup_pm_suspend_runtime(struct device *device)
> > +{
> > + struct spi_master *master = dev_get_drvdata(device);
> > + struct spi_qup *controller = spi_master_get_devdata(master);
> > +
> > + disable_irq(controller->irq);
>
> Why do you need to disable the interrupt? Will the hardware generate
> spurious interrupts, if so some documentation is in order.
I don't know. Just extra protection? I will have t o find how to
test this.
>
> > +static int spi_qup_pm_resume_runtime(struct device *device)
> > +{
> > + struct spi_master *master = dev_get_drvdata(device);
> > + struct spi_qup *controller = spi_master_get_devdata(master);
> > +
> > + clk_prepare_enable(controller->cclk);
> > + clk_prepare_enable(controller->iclk);
> > + enable_irq(controller->irq);
>
> No error checking here...
Will fix.
Thanks,
Ivan
next prev parent reply other threads:[~2014-02-10 16:29 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-06 16:57 [PATCH 0/2] spi: Add Qualcomm QUP SPI controller support Ivan T. Ivanov
2014-02-06 16:57 ` [PATCH 1/2] spi: qup: Add device tree bindings information Ivan T. Ivanov
[not found] ` <1391705868-20091-2-git-send-email-iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
2014-02-07 7:43 ` Andy Gross
2014-02-07 7:43 ` Andy Gross
2014-02-06 16:57 ` [PATCH 2/2] spi: Add Qualcomm QUP SPI controller support Ivan T. Ivanov
2014-02-07 7:39 ` Andy Gross
[not found] ` <20140207073952.GA2610-zC7DfRvBq/JWk0Htik3J/w@public.gmane.org>
2014-02-07 9:52 ` Ivan T. Ivanov
2014-02-07 9:52 ` Ivan T. Ivanov
2014-02-07 17:32 ` Andy Gross
2014-02-07 17:32 ` Andy Gross
2014-02-07 17:52 ` Mark Brown
[not found] ` <20140207175234.GJ1757-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-02-07 19:12 ` Andy Gross
2014-02-07 19:12 ` Andy Gross
2014-02-10 16:55 ` Ivan T. Ivanov
2014-02-10 17:47 ` Andy Gross
2014-02-10 17:47 ` Andy Gross
[not found] ` <20140210174738.GA31596-zC7DfRvBq/JWk0Htik3J/w@public.gmane.org>
2014-02-10 19:41 ` Ivan T. Ivanov
2014-02-10 19:41 ` Ivan T. Ivanov
2014-02-10 20:29 ` Courtney Cavin
2014-02-10 20:59 ` Ivan T. Ivanov
2014-02-10 21:40 ` Mark Brown
2014-02-10 21:40 ` Mark Brown
[not found] ` <20140210202926.GV1706-/MT0OVThwyLZJqsBc5GL+g@public.gmane.org>
2014-02-11 15:46 ` Ivan T. Ivanov
2014-02-11 15:46 ` Ivan T. Ivanov
2014-02-07 16:51 ` Josh Cartwright
[not found] ` <20140207165127.GV20228-OP5zVEFNDbfdOxZ39nK119BPR1lH4CV8@public.gmane.org>
2014-02-07 17:18 ` Mark Brown
2014-02-07 17:18 ` Mark Brown
2014-02-07 17:20 ` Josh Cartwright
[not found] ` <20140207172051.GW20228-OP5zVEFNDbfdOxZ39nK119BPR1lH4CV8@public.gmane.org>
2014-02-07 17:31 ` Mark Brown
2014-02-07 17:31 ` Mark Brown
[not found] ` <20140207173108.GH1757-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-02-07 17:46 ` Josh Cartwright
2014-02-07 17:46 ` Josh Cartwright
2014-02-07 17:57 ` Mark Brown
[not found] ` <CACceFXdUobQvN2hcv5kh+QL=o8bWM_PVkAtrOx+euZSeVDm8hQ@mail.gmail.com>
2014-02-07 16:34 ` Fwd: " dsneddon
2014-02-07 17:16 ` Mark Brown
[not found] ` <214fe9fc7e62ab30bdfbb4ac5d1ee250.squirrel-mMfbam+mt9083fI46fginR2eb7JE58TQ@public.gmane.org>
2014-02-10 15:54 ` Ivan T. Ivanov
2014-02-10 16:21 ` dsneddon
[not found] ` <3388d68dc907e9190d997fad95830d74.squirrel-mMfbam+mt9083fI46fginR2eb7JE58TQ@public.gmane.org>
2014-02-10 17:11 ` Ivan T. Ivanov
2014-02-10 17:41 ` dsneddon
[not found] ` <1391705868-20091-3-git-send-email-iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
2014-02-07 17:12 ` Mark Brown
2014-02-07 17:12 ` Mark Brown
[not found] ` <20140207171202.GD1757-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-02-10 16:29 ` Ivan T. Ivanov [this message]
2014-02-10 16:29 ` Ivan T. Ivanov
2014-02-10 17:09 ` Mark Brown
2014-02-10 17:09 ` Mark Brown
2014-02-06 17:50 ` [PATCH 0/2] " Mark Brown
2014-02-07 7:43 ` [PATCH RESEND 1/2] spi: qup: Add device tree bindings information Ivan T. Ivanov
2014-02-07 12:27 ` Mark Brown
2014-02-07 13:00 ` Ivan T. Ivanov
2014-02-07 13:13 ` Mark Brown
2014-02-07 13:35 ` Ivan T. Ivanov
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=1392049766.2853.43.camel@iivanov-dev \
--to=iivanov-neyub+7iv8pqt0dzr+alfa@public.gmane.org \
--cc=alokc-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
--cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=gavidov-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
--cc=grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=kgunda-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
--cc=linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-spi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=sdharia-sgV2jX0FEOL9JmXXK+q4OQ@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.