From: Vipin Kumar <vipin.kumar@st.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH resend] spi/arm-pl022: Add support for ARM PL022 spi controller
Date: Wed, 12 Dec 2012 16:02:28 +0530 [thread overview]
Message-ID: <50C85D3C.3050104@st.com> (raw)
In-Reply-To: <50C859F5.6020907@denx.de>
On 12/12/2012 3:48 PM, Stefan Roese wrote:
> On 12/06/2012 07:56 AM, Vipin Kumar wrote:
>> From: Armando Visconti<armando.visconti@st.com>
>>
>> This patch adds the support for the ARM PL022 SPI controller for the standard
>> variant (0x00041022), which has a 16bit wide and 8 locations deep TX/RX FIFO.
>>
>> Signed-off-by: Armando Visconti<armando.visconti@st.com>
>> Signed-off-by: Vipin Kumar<vipin.kumar@st.com>
>> ---
>>
>> Dear Wolfgang, Stefan,
>>
>> There seems to be no direct owner of spi framework. So, I am directing this
>> patch to you
>
> A few comments below.
>
>> Regards
>> Vipin
>>
>> drivers/spi/Makefile | 1 +
>> drivers/spi/pl022_spi.c | 308 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 309 insertions(+)
>> create mode 100644 drivers/spi/pl022_spi.c
>>
>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
>> index 824d357..3a4e4b0 100644
>> --- a/drivers/spi/Makefile
>> +++ b/drivers/spi/Makefile
>> @@ -42,6 +42,7 @@ COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
>> COBJS-$(CONFIG_MXS_SPI) += mxs_spi.o
>> COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
>> COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
>> +COBJS-$(CONFIG_PL022_SPI) += pl022_spi.o
>> COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
>> COBJS-$(CONFIG_SH_SPI) += sh_spi.o
>> COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
>> diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c
>> new file mode 100644
>> index 0000000..3ea769a
>> --- /dev/null
>> +++ b/drivers/spi/pl022_spi.c
>> @@ -0,0 +1,308 @@
>> +/*
>> + * (C) Copyright 2012
>> + * Armando Visconti, ST Microelectronics, armando.visconti at st.com.
>> + *
>> + * Driver for ARM PL022 SPI Controller. Based on atmel_spi.c
>> + * by Atmel Corporation.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
>> + * MA 02111-1307 USA
>> + */
>> +
>> +#include<common.h>
>> +#include<malloc.h>
>> +#include<spi.h>
>> +#include<asm/io.h>
>> +#include<asm/arch/hardware.h>
>> +
>> +/* SSP registers mapping */
>> +#define SSP_CR0 0x000
>> +#define SSP_CR1 0x004
>> +#define SSP_DR 0x008
>> +#define SSP_SR 0x00C
>> +#define SSP_CPSR 0x010
>> +#define SSP_IMSC 0x014
>> +#define SSP_RIS 0x018
>> +#define SSP_MIS 0x01C
>> +#define SSP_ICR 0x020
>> +#define SSP_DMACR 0x024
>> +#define SSP_ITCR 0x080
>> +#define SSP_ITIP 0x084
>> +#define SSP_ITOP 0x088
>> +#define SSP_TDR 0x08C
>
> Please use C-structs instead to access the registers.
>
May be this patch is a ripped version from linux. That's why
Thanks. I will do this in v2
>> +#define SSP_PID0 0xFE0
>> +#define SSP_PID1 0xFE4
>> +#define SSP_PID2 0xFE8
>> +#define SSP_PID3 0xFEC
>> +
>> +#define SSP_CID0 0xFF0
>> +#define SSP_CID1 0xFF4
>> +#define SSP_CID2 0xFF8
>> +#define SSP_CID3 0xFFC
>> +
>> +/* SSP Control Register 0 - SSP_CR0 */
>> +#define SSP_CR0_SPO (0x1<< 6)
>> +#define SSP_CR0_SPH (0x1<< 7)
>> +#define SSP_CR0_8BIT_MODE (0x07)
>> +#define SSP_SCR_MAX (0xFF)
>> +#define SSP_SCR_SHFT 8
>> +
>> +/* SSP Control Register 0 - SSP_CR1 */
>> +#define SSP_CR1_MASK_SSE (0x1<< 1)
>> +
>> +#define SSP_CPSR_MAX (0xFE)
>> +
>> +/* SSP Status Register - SSP_SR */
>> +#define SSP_SR_MASK_TFE (0x1<< 0) /* Transmit FIFO empty */
>> +#define SSP_SR_MASK_TNF (0x1<< 1) /* Transmit FIFO not full */
>> +#define SSP_SR_MASK_RNE (0x1<< 2) /* Receive FIFO not empty */
>> +#define SSP_SR_MASK_RFF (0x1<< 3) /* Receive FIFO full */
>> +#define SSP_SR_MASK_BSY (0x1<< 4) /* Busy Flag */
>> +
>> +struct pl022_spi_slave {
>> + struct spi_slave slave;
>> + void *regs;
>> + unsigned int freq;
>> +};
>> +
>> +static inline struct pl022_spi_slave *to_pl022_spi(struct spi_slave *slave)
>> +{
>> + return container_of(slave, struct pl022_spi_slave, slave);
>> +}
>> +
>> +/*
>> + * Following three functions should be provided by the
>> + * board support package.
>> + */
>> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
>> + __attribute__((weak, alias("__spi_cs_is_valid")));
>> +void spi_cs_activate(struct spi_slave *slave)
>> + __attribute__((weak, alias("__spi_cs_activate")));
>> +void spi_cs_deactivate(struct spi_slave *slave)
>> + __attribute__((weak, alias("__spi_cs_deactivate")));
>
> __weak from linux/compiler.h
>
OK
>> +int __spi_cs_is_valid(unsigned int bus, unsigned int cs)
>> +{
>> + return 1;
>> +}
>> +
>> +void __spi_cs_activate(struct spi_slave *slave)
>> +{
>> + /* do nothing */
>> +}
>> +
>> +void __spi_cs_deactivate(struct spi_slave *slave)
>> +{
>> + /* do nothing */
>> +}
>> +
>> +void spi_init()
>> +{
>> + /* do nothing */
>> +}
>> +
>> +/*
>> + * ARM PL022 exists in different 'flavors'.
>> + * This drivers currently support the standard variant (0x00041022), that has a
>> + * 16bit wide and 8 locations deep TX/RX FIFO.
>> + */
>> +static int pl022_is_supported(struct pl022_spi_slave *ps)
>> +{
>> + /* PL022 version is 0x00041022 */
>> + if ((readw(ps->regs + SSP_PID0) == 0x22)&&
>> + (readw(ps->regs + SSP_PID1) == 0x10)&&
>> + ((readw(ps->regs + SSP_PID2)& 0xf) == 0x04)&&
>> + (readw(ps->regs + SSP_PID3) == 0x00))
>> + return 1;
>> +
>> + return 0;
>> +}
>> +
>> +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
>> + unsigned int max_hz, unsigned int mode)
>> +{
>> + struct pl022_spi_slave *ps;
>> + u16 scr = 1, prescaler, cr0 = 0, cpsr = 0;
>> +
>> + if (!spi_cs_is_valid(bus, cs))
>> + return NULL;
>> +
>> + ps = malloc(sizeof(*ps));
>> + if (!ps)
>> + return NULL;
>> +
>> + ps->slave.bus = bus;
>> + ps->slave.cs = cs;
>> + ps->freq = max_hz;
>> +
>> + switch (bus) {
>> + case 0:
>> + ps->regs = (void *)CONFIG_SYS_SPI_BASE;
>> + break;
>> +#ifdef CONFIG_SYS_SPI_BASE1
>> + case 1:
>> + ps->regs = (void *)CONFIG_SYS_SPI_BASE1;
>> + break;
>> +#endif
>> +#ifdef CONFIG_SYS_SPI_BASE2
>> + case 2:
>> + ps->regs = (void *)CONFIG_SYS_SPI_BASE2;
>> + break;
>> +#endif
>> +#ifdef CONFIG_SYS_SPI_BASE3
>> + case 3:
>> + ps->regs = (void *)CONFIG_SYS_SPI_BASE3;
>> + break;
>> +#endif
>> + default:
>> + free(ps);
>> + return NULL;
>> + }
>> +
>> + /* Check the PL022 version */
>> + if (!pl022_is_supported(ps)) {
>> + free(ps);
>> + return NULL;
>> + }
>> +
>> + /* Set requested polarity and 8bit mode */
>> + cr0 = SSP_CR0_8BIT_MODE;
>> + cr0 |= (mode& SPI_CPHA) ? SSP_CR0_SPH : 0;
>> + cr0 |= (mode& SPI_CPOL) ? SSP_CR0_SPO : 0;
>> +
>> + writew(cr0, ps->regs + SSP_CR0);
>> +
>> + /* Program the SSPClk frequency */
>> + prescaler = CONFIG_SYS_SPI_CLK / ps->freq;
>> +
>> + if (prescaler<= 0xFF)
>> + cpsr = prescaler;
>> + else {
>> + for (scr = 1; scr<= SSP_SCR_MAX; scr++) {
>> + if (!(prescaler % scr)) {
>> + cpsr = prescaler / scr;
>> + if (cpsr<= SSP_CPSR_MAX)
>> + break;
>> + }
>> + }
>> +
>> + if (scr> SSP_SCR_MAX) {
>> + scr = SSP_SCR_MAX;
>> + cpsr = prescaler / scr;
>> + cpsr&= SSP_CPSR_MAX;
>> + }
>> + }
>> +
>> + if (cpsr& 0x1)
>> + cpsr++;
>> +
>> + writew(cpsr, ps->regs + SSP_CPSR);
>> + cr0 = readw(ps->regs + SSP_CR0);
>> + writew(cr0 | (scr - 1)<< SSP_SCR_SHFT, ps->regs + SSP_CR0);
>> +
>> + return&ps->slave;
>> +}
>> +
>> +void spi_free_slave(struct spi_slave *slave)
>> +{
>> + struct pl022_spi_slave *ps = to_pl022_spi(slave);
>> +
>> + free(ps);
>> +}
>> +
>> +int spi_claim_bus(struct spi_slave *slave)
>> +{
>> + struct pl022_spi_slave *ps = to_pl022_spi(slave);
>> +
>> + /* Enable the SPI hardware */
>> + writew(readw(ps->regs + SSP_CR1) | SSP_CR1_MASK_SSE,
>> + ps->regs + SSP_CR1);
>> +
>> + return 0;
>> +}
>> +
>> +void spi_release_bus(struct spi_slave *slave)
>> +{
>> + struct pl022_spi_slave *ps = to_pl022_spi(slave);
>> +
>> + /* Disable the SPI hardware */
>> + writew(0x0, ps->regs + SSP_CR1);
>> +}
>> +
>> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>> + const void *dout, void *din, unsigned long flags)
>> +{
>> + struct pl022_spi_slave *ps = to_pl022_spi(slave);
>> + u32 len_tx = 0, len_rx = 0, len;
>> + u32 ret = 0;
>> + const u8 *txp = dout;
>> + u8 *rxp = din, value;
>> +
>> + if (bitlen == 0)
>> + /* Finish any previously submitted transfers */
>> + goto out;
>> +
>> + /*
>> + * TODO: The controller can do non-multiple-of-8 bit
>> + * transfers, but this driver currently doesn't support it.
>> + *
>> + * It's also not clear how such transfers are supposed to be
>> + * represented as a stream of bytes...this is a limitation of
>> + * the current SPI interface.
>> + */
>> + if (bitlen % 8) {
>> + ret = -1;
>> +
>> + /* Errors always terminate an ongoing transfer */
>> + flags |= SPI_XFER_END;
>> + goto out;
>> + }
>> +
>> + len = bitlen / 8;
>> +
>> + if (flags& SPI_XFER_BEGIN)
>> + spi_cs_activate(slave);
>> +
>> + while (len_tx< len) {
>> + if (readw(ps->regs + SSP_SR)& SSP_SR_MASK_TNF) {
>> + value = (txp != NULL) ? *txp++ : 0;
>> + writew(value, ps->regs + SSP_DR);
>> + len_tx++;
>> + }
>> +
>> + if (readw(ps->regs + SSP_SR)& SSP_SR_MASK_RNE) {
>> + value = readw(ps->regs + SSP_DR);
>> + if (rxp)
>> + *rxp++ = value;
>> + len_rx++;
>> + }
>> + }
>> +
>> + while (len_rx< len_tx) {
>> + if (readw(ps->regs + SSP_SR)& SSP_SR_MASK_RNE) {
>> + value = readw(ps->regs + SSP_DR);
>> + if (rxp)
>> + *rxp++ = value;
>> + len_rx++;
>> + }
>> + }
>> +
>> +out:
>> + if (flags& SPI_XFER_END)
>> + spi_cs_deactivate(slave);
>> +
>> + return ret;
>> +}
>
> Looks good.
>
Thanks..will send v2 very soon
> Thanks,
> Stefan
>
> .
>
next prev parent reply other threads:[~2012-12-12 10:32 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-12-06 6:56 [U-Boot] [PATCH resend] spi/arm-pl022: Add support for ARM PL022 spi controller Vipin Kumar
2012-12-06 8:05 ` Stefan Roese
2012-12-12 10:00 ` Vipin Kumar
2012-12-12 10:18 ` Stefan Roese
2012-12-12 10:32 ` Vipin Kumar [this message]
2012-12-12 11:10 ` Armando Visconti
2012-12-12 11:15 ` Vipin Kumar
2012-12-12 11:29 ` Stefan Roese
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=50C85D3C.3050104@st.com \
--to=vipin.kumar@st.com \
--cc=u-boot@lists.denx.de \
/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.