From patchwork Thu Sep 2 07:51:59 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Wang X-Patchwork-Id: 148581 Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o827n6EJ002802 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 2 Sep 2010 07:50:13 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-4.v29.ch3.sourceforge.com) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1Or4Xb-0007ZO-Lv; Thu, 02 Sep 2010 07:48:59 +0000 Received: from sog-mx-3.v43.ch3.sourceforge.com ([172.29.43.193] helo=mx.sourceforge.net) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1Or4Xa-0007Yq-6R for spi-devel-general@lists.sourceforge.net; Thu, 02 Sep 2010 07:48:58 +0000 Received-SPF: neutral (sog-mx-3.v43.ch3.sourceforge.com: 147.11.1.11 is neither permitted nor denied by domain of gmail.com) client-ip=147.11.1.11; envelope-from=jason77.wang@gmail.com; helo=mail.windriver.com; Received: from mail.windriver.com ([147.11.1.11]) by sog-mx-3.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.69) id 1Or4XZ-0002oM-8w for spi-devel-general@lists.sourceforge.net; Thu, 02 Sep 2010 07:48:58 +0000 Received: from ALA-MAIL03.corp.ad.wrs.com (ala-mail03 [147.11.57.144]) by mail.windriver.com (8.14.3/8.14.3) with ESMTP id o827mkHU027726; Thu, 2 Sep 2010 00:48:46 -0700 (PDT) Received: from localhost.localdomain ([128.224.163.220]) by ALA-MAIL03.corp.ad.wrs.com with Microsoft SMTPSVC(6.0.3790.1830); Thu, 2 Sep 2010 00:48:45 -0700 From: Jason Wang To: s.hauer@pengutronix.de, u.kleine-koenig@pengutronix.de, amit.kucheria@canonical.com, grant.likely@secretlab.ca Subject: [PATCH 1/6] spi-imx: add CSPI and eCSPI support for i.MX51 MCU Date: Thu, 2 Sep 2010 15:51:59 +0800 Message-Id: <1283413924-14210-2-git-send-email-jason77.wang@gmail.com> X-Mailer: git-send-email 1.5.6.5 In-Reply-To: <1283413924-14210-1-git-send-email-jason77.wang@gmail.com> References: <1283413924-14210-1-git-send-email-jason77.wang@gmail.com> X-OriginalArrivalTime: 02 Sep 2010 07:48:46.0078 (UTC) FILETIME=[45ABE9E0:01CB4A73] X-Spam-Score: 1.9 (+) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 FREEMAIL_FROM Sender email is freemail (jason77.wang[at]gmail.com) 0.0 DKIM_ADSP_CUSTOM_MED No valid author signature, adsp_override is CUSTOM_MED 0.7 SPF_NEUTRAL SPF: sender does not match SPF record (neutral) 1.2 NML_ADSP_CUSTOM_MED ADSP custom_med hit, and not from a mailing list 0.0 T_TO_NO_BRKTS_FREEMAIL T_TO_NO_BRKTS_FREEMAIL X-Headers-End: 1Or4XZ-0002oM-8w Cc: spi-devel-general@lists.sourceforge.net, linux-arm-kernel@lists.infradead.org X-BeenThere: spi-devel-general@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux SPI core/device drivers discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: spi-devel-general-bounces@lists.sourceforge.net X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 02 Sep 2010 07:50:13 +0000 (UTC) diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 7972e90..8d9c9da 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -155,6 +155,120 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, return 7; } +/* MX51 eCSPI post divider */ +static unsigned int spi_imx_clkdiv_3(unsigned int fin, + unsigned int fspi) +{ + int i, div = 1; + + for (i = 0; i < 15; i++) { + if (fspi * div >= fin) + return i; + div <<= 1; + } + + return 15; +} + +#define MX51_INTREG_TEEN (1 << 0) +#define MX51_INTREG_RREN (1 << 3) + +#define MX51_CSPICTRL_ENABLE (1 << 0) +#define MX51_CSPICTRL_XCH (1 << 2) + +#define MX51_CSPICTRL_BL_SHIFT 20 +#define MX51_CSPICTRL_CS_SHIFT 18 +#define MX51_CSPICTRL_DR_SHIFT 8 +#define MX51_CSPICTRL_MODE_SHIFT 4 +#define MX51_CSPICONF_PHA_SHIFT 0 +#define MX51_CSPICONF_POL_SHIFT 4 +#define MX51_CSPICONF_SSPOL_SHIFT 12 +#define MX51_CSPICONF_SSCTL_SHIFT 8 + +#define MX51_CSPICTRL_CSMASK 0x3 +#define MX51_CSPIINT 0x10 +#define MX51_CSPICONF 0xC +#define MX51_CSPISTATUS 0x18 +#define MX51_STATUS_RR (1 << 3) + +#define MAX_CHIPSELECT_NUM 4 + +static int get_chipselect(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) +{ + int i; + + for (i = 0; i < MAX_CHIPSELECT_NUM; i++) { + if (config->cs == spi_imx->chipselect[i]) + return i; + } + + return -EINVAL; +} +static void mx51_intctrl(struct spi_imx_data *spi_imx, int enable) +{ + unsigned int val = 0; + + if (enable & MXC_INT_TE) + val |= MX51_INTREG_TEEN; + if (enable & MXC_INT_RR) + val |= MX51_INTREG_RREN; + + writel(val, spi_imx->base + MX51_CSPIINT); +} + +static void mx51_trigger(struct spi_imx_data *spi_imx) +{ + unsigned int reg; + + reg = readl(spi_imx->base + MXC_CSPICTRL); + reg |= MX51_CSPICTRL_XCH; + writel(reg, spi_imx->base + MXC_CSPICTRL); +} + +static int mx51_config(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) +{ + unsigned int config_reg = 0; + unsigned int ctrl_reg = MX51_CSPICTRL_ENABLE; + int chan; + + chan = get_chipselect(spi_imx, config); + if (chan < 0) + return chan; + ctrl_reg |= (chan & MX51_CSPICTRL_CSMASK) << MX51_CSPICTRL_CS_SHIFT; + ctrl_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) << + MX51_CSPICTRL_MODE_SHIFT; + ctrl_reg |= spi_imx_clkdiv_3(spi_imx->spi_clk, config->speed_hz) << + MX51_CSPICTRL_DR_SHIFT; + + ctrl_reg |= (config->bpw - 1) << MX51_CSPICTRL_BL_SHIFT; + + + if (config->mode & SPI_CPHA) + config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) << + MX51_CSPICONF_PHA_SHIFT; + if (config->mode & SPI_CPOL) + config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) << + MX51_CSPICONF_POL_SHIFT; + if (config->mode & SPI_CS_HIGH) + config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) << + MX51_CSPICONF_SSPOL_SHIFT; + + config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) << + MX51_CSPICONF_SSCTL_SHIFT; + + writel(ctrl_reg, spi_imx->base + MXC_CSPICTRL); + writel(config_reg, spi_imx->base + MX51_CSPICONF); + + return 0; +} + +static int mx51_rx_available(struct spi_imx_data *spi_imx) +{ + return readl(spi_imx->base + MX51_CSPISTATUS) & MX51_STATUS_RR; +} + #define MX31_INTREG_TEEN (1 << 0) #define MX31_INTREG_RREN (1 << 3) @@ -209,7 +323,7 @@ static int mx31_config(struct spi_imx_data *spi_imx, if (cpu_is_mx31()) reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT; - else if (cpu_is_mx25() || cpu_is_mx35()) { + else if (cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()) { reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; reg |= MX31_CSPICTRL_SSCTL; } @@ -223,7 +337,7 @@ static int mx31_config(struct spi_imx_data *spi_imx, if (config->cs < 0) { if (cpu_is_mx31()) reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT; - else if (cpu_is_mx25() || cpu_is_mx35()) + else if (cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()) reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT; } @@ -567,7 +681,14 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) goto out_iounmap; } - if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) { + /* i.MX51 has two eCSPI and one CSPI controllers, eCSPI controllers are + * not compatible with existing SPI controllers on other i.MX platforms, + * while CSPI controller is 100% compatible with the one on the i.MX35. + * We set the platform device id to 2 for this CSPI at i.MX51 board init + * level to distinguish it from two eCSPI controllers. + */ + if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35() || + (cpu_is_mx51() && (pdev->id == 2))) { spi_imx->intctrl = mx31_intctrl; spi_imx->config = mx31_config; spi_imx->trigger = mx31_trigger; @@ -582,6 +703,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) spi_imx->config = mx1_config; spi_imx->trigger = mx1_trigger; spi_imx->rx_available = mx1_rx_available; + } else if (cpu_is_mx51()) { + spi_imx->intctrl = mx51_intctrl; + spi_imx->config = mx51_config; + spi_imx->trigger = mx51_trigger; + spi_imx->rx_available = mx51_rx_available; } else BUG(); @@ -599,7 +725,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) writel(1, spi_imx->base + MXC_RESET); /* drain receive buffer */ - if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) + if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35() || + (cpu_is_mx51() && (pdev->id == 2))) while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR) readl(spi_imx->base + MXC_CSPIRXDATA);