From patchwork Fri Jan 16 07:19:17 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Albert ARIBAUD (3ADEV)" X-Patchwork-Id: 429750 X-Patchwork-Delegate: jagannadh.teki@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id B40151401DA for ; Fri, 16 Jan 2015 18:37:54 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 23ED54B659; Fri, 16 Jan 2015 08:37:38 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zKRM6q3yYL3B; Fri, 16 Jan 2015 08:37:37 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B58664B686; Fri, 16 Jan 2015 08:37:13 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2E9CA4B61A for ; Fri, 16 Jan 2015 08:20:32 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id dgp7AoVNWuhy for ; Fri, 16 Jan 2015 08:20:32 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from smtp2-g21.free.fr (smtp2-g21.free.fr [212.27.42.2]) by theia.denx.de (Postfix) with ESMTPS id 039474B615 for ; Fri, 16 Jan 2015 08:20:31 +0100 (CET) Received: from localhost.localdomain (unknown [IPv6:2a01:e35:2eb9:21:d504:b12c:7b53:5149]) (Authenticated sender: aribaud.smtp) by smtp2-g21.free.fr (Postfix) with ESMTPSA id 845D54B0239; Fri, 16 Jan 2015 08:18:07 +0100 (CET) From: "Albert ARIBAUD (3ADEV)" To: u-boot@lists.denx.de Date: Fri, 16 Jan 2015 08:19:17 +0100 Message-Id: <1421392760-21810-6-git-send-email-albert.aribaud@3adev.fr> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1421392760-21810-5-git-send-email-albert.aribaud@3adev.fr> References: <1421392760-21810-1-git-send-email-albert.aribaud@3adev.fr> <1421392760-21810-2-git-send-email-albert.aribaud@3adev.fr> <1421392760-21810-3-git-send-email-albert.aribaud@3adev.fr> <1421392760-21810-4-git-send-email-albert.aribaud@3adev.fr> <1421392760-21810-5-git-send-email-albert.aribaud@3adev.fr> X-Mailman-Approved-At: Fri, 16 Jan 2015 08:37:02 +0100 Cc: "Albert ARIBAUD \(3ADEV\)" Subject: [U-Boot] [PATCH v1 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.13 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Signed-off-by: Albert ARIBAUD (3ADEV) --- arch/arm/cpu/arm926ejs/lpc32xx/devices.c | 6 ++ arch/arm/include/asm/arch-lpc32xx/clk.h | 3 + arch/arm/include/asm/arch-lpc32xx/sys_proto.h | 1 + drivers/spi/Makefile | 1 + drivers/spi/lpc32xx_ssp.c | 132 ++++++++++++++++++++++++++ 5 files changed, 143 insertions(+) create mode 100644 drivers/spi/lpc32xx_ssp.c diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c index 81b53ea..56ce9ab 100644 --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c @@ -61,3 +61,9 @@ void lpc32xx_i2c_init(unsigned int devnum) ctrl |= CLK_I2C2_ENABLE; writel(ctrl, &clk->i2cclk_ctrl); } + +void lpc32xx_ssp_init(void) +{ + /* Enable SSP0 interface */ + writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl); +} diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h index 781ac07..2cb5703 100644 --- a/arch/arm/include/asm/arch-lpc32xx/clk.h +++ b/arch/arm/include/asm/arch-lpc32xx/clk.h @@ -155,6 +155,9 @@ struct clk_pm_regs { #define CLK_NAND_MLC (1 << 1) #define CLK_NAND_MLC_INT (1 << 5) +/* SSP Clock Control Register bits */ +#define CLK_SSP0_ENABLE_CLOCK (1 << 0) + unsigned int get_sys_clk_rate(void); unsigned int get_hclk_pll_rate(void); unsigned int get_hclk_clk_div(void); diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h index a4a05d1..86d5ee9 100644 --- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h +++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h @@ -11,5 +11,6 @@ void lpc32xx_uart_init(unsigned int uart_id); void lpc32xx_mac_init(void); void lpc32xx_mlc_nand_init(void); void lpc32xx_i2c_init(unsigned int devnum); +void lpc32xx_ssp_init(void); #endif /* _LPC32XX_SYS_PROTO_H */ diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index edbd520..ce6f1cc 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o obj-$(CONFIG_ICH_SPI) += ich.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o +obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o obj-$(CONFIG_MXC_SPI) += mxc_spi.o diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c new file mode 100644 index 0000000..40270df --- /dev/null +++ b/drivers/spi/lpc32xx_ssp.c @@ -0,0 +1,132 @@ +/* + * LPC32xx SSP interface (SPI mode) + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +/* SSP chip registers */ +struct ssp_regs { + u32 cr0; + u32 cr1; + u32 data; + u32 sr; + u32 cpsr; + u32 imsc; + u32 ris; + u32 mis; + u32 icr; + u32 dmacr; +}; + +/* CR1 register defines */ +#define SSP_CR1_SSP_ENABLE 0x0002 + +/* SR register defines */ +#define SSP_SR_TNF 0x0002 +/* SSP status RX FIFO not empty bit */ +#define SSP_SR_RNE 0x0004 + +static struct ssp_regs *ssp0_regs = (struct ssp_regs *)SSP0_BASE; + +static struct spi_slave ssp0_slave = { + .bus = 0, + .cs = 0, + .op_mode_rx = 0, + .op_mode_tx = 0, + .wordlen = 8, + .max_write_size = 1, /* this is for SPI FLASHes -- don't care */ + .memory_map = NULL, /* for SPI FLASHes too */ + .option = 0, + .flags = 0 +}; + +/* spi_init is called during boot when CONFIG_CMD_SPI is defined */ +void spi_init(void) +{ + /* + * nothing to do: clocking was enabled in lpc32xx_ssp_enable() + * and configuration will be done in spi_setup_slave() + */ +} + +/* the following is called in sequence by do_spi_xfer() */ + +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) +{ + /* we only set up SSP0 for now, so ignore bus */ + + if (mode & SPI_3WIRE) { + error("3-wire mode not supported"); + return NULL; + } + + if (mode & SPI_SLAVE) { + error("slave mode not supported\n"); + return NULL; + } + + if (mode & SPI_PREAMBLE) { + error("preamble byte skipping not supported\n"); + return NULL; + } + + /* + * 8 bit frame, SPI fmt, 500kbps -> clock divider is 26. + * Set SCR to 0 and CPSDVSR to 26. + */ + + writel(0x7, &ssp0_regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */ + writel(26, &ssp0_regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */ + writel(0, &ssp0_regs->imsc); /* do not raise any interrupts */ + writel(0, &ssp0_regs->icr); /* clear any pending interrupt */ + writel(0, &ssp0_regs->dmacr); /* do not do DMAs */ + writel(SSP_CR1_SSP_ENABLE, &ssp0_regs->cr1); /* enable SSP0 */ + return &ssp0_slave; +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* only one bus and slave so far, always available */ + return 0; +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + int bytelen = bitlen >> 3; + int idx_out = 0; + int idx_in = 0; + int start_time; + + start_time = get_timer(0); + while ((idx_out < bytelen) || (idx_in < bytelen)) { + int status = readl(&ssp0_regs->sr); + if ((idx_out < bytelen) && (status & SSP_SR_TNF)) + writel(((u8 *)dout)[idx_out++], &ssp0_regs->data); + if ((idx_in < bytelen) && (status & status & SSP_SR_RNE)) + ((u8 *)din)[idx_in++] = readl(&ssp0_regs->data); + if (get_timer(start_time) >= CONFIG_LPC32XX_SSP_TIMEOUT) + return -1; + } + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* do nothing */ +} + +void spi_free_slave(struct spi_slave *slave) +{ + /* do nothing */ +}