From patchwork Mon Oct 22 11:52:07 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hatim Ali X-Patchwork-Id: 12398 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id B747223EF8 for ; Mon, 22 Oct 2012 11:59:20 +0000 (UTC) Received: from mail-ia0-f180.google.com (mail-ia0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 512C9A1855B for ; Mon, 22 Oct 2012 11:59:20 +0000 (UTC) Received: by mail-ia0-f180.google.com with SMTP id f6so1913223iag.11 for ; Mon, 22 Oct 2012 04:59:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:x-auditid :from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :dlp-filter:x-mtr:x-brightmail-tracker:x-brightmail-tracker :x-cfilter-loop:x-gm-message-state; bh=n9zBpkG5DZSD1DsGYXxpzkLKf3qd5EfoKUeUvJjpAZk=; b=hvyjxQ2RmB39YzCyDUGrmp2IFstE37O/EpmmVwnldnnFETBU/mvr9MBfRLzyFPaCg5 k0XpotRlx5N/aeBKUD531/nZ8yEIG2vt9EMWlf2BNJDEwYuS1497Tp3NDitK10e9zStl APYCph1PBiBUHwTLMBlCkzt/wwezyMbgwSk3mY8qihzOytIbppGDPo+7Cr0plEp/AYln KKr8zl9EER+TaTnNnykpktTQ1FmW7yUmHziR3bG+AnzdnTG/OeBHInqottFNotkWVX6d Zz5PqH9xolqOIR8KwKt+dcqbeZPwZLSGVbS1xCxdvW9T6z4gOqecvU4nlEXiHWgol/zw 59kA== Received: by 10.50.91.195 with SMTP id cg3mr15841146igb.57.1350907159510; Mon, 22 Oct 2012 04:59:19 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.67.148 with SMTP id n20csp218681igt; Mon, 22 Oct 2012 04:59:18 -0700 (PDT) Received: by 10.68.232.195 with SMTP id tq3mr29352084pbc.70.1350907158449; Mon, 22 Oct 2012 04:59:18 -0700 (PDT) Received: from mailout3.samsung.com (mailout3.samsung.com. [203.254.224.33]) by mx.google.com with ESMTP id rl8si13490735pbc.292.2012.10.22.04.59.17; Mon, 22 Oct 2012 04:59:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of hatim.rv@samsung.com designates 203.254.224.33 as permitted sender) client-ip=203.254.224.33; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of hatim.rv@samsung.com designates 203.254.224.33 as permitted sender) smtp.mail=hatim.rv@samsung.com Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MCA0058PMMFPFT0@mailout3.samsung.com> for patches@linaro.org; Mon, 22 Oct 2012 20:59:17 +0900 (KST) Received: from epcpsbgm2.samsung.com ( [172.20.52.124]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id A3.20.12699.51535805; Mon, 22 Oct 2012 20:59:17 +0900 (KST) X-AuditID: cbfee61b-b7f616d00000319b-57-508535158044 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 63.20.12699.41535805; Mon, 22 Oct 2012 20:59:16 +0900 (KST) Received: from hatim-linux.sisodomain.com ([107.108.73.95]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MCA006A7MH2ZQ10@mmp1.samsung.com> for patches@linaro.org; Mon, 22 Oct 2012 20:59:16 +0900 (KST) From: Hatim Ali To: u-boot@lists.denx.de Cc: sjg@chromium.org, promsoft@gmail.com, patches@linaro.org Subject: [PATCH 4/6 V7] SPI: Add SPI Driver for EXYNOS. Date: Mon, 22 Oct 2012 17:22:07 +0530 Message-id: <1350906729-23749-5-git-send-email-hatim.rv@samsung.com> X-Mailer: git-send-email 1.7.2.3 In-reply-to: <1350906729-23749-1-git-send-email-hatim.rv@samsung.com> References: <1350906729-23749-1-git-send-email-hatim.rv@samsung.com> DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrFLMWRmVeSWpSXmKPExsWyRsSkRlfUtDXA4PBhXosph7+wODB63Lm2 hy2AMYrLJiU1J7MstUjfLoErY9veG6wF7/IqTjZMYGxgnBbZxcjJISFgIjGro5kRwhaTuHBv PVsXIxeHkMBSRokp3w8ywhRN7bzPBmILCSxilFh2RhWiaBGTxM2uc2BFbAJqEutfd4IViQhI SPzqvwoWZxawkVjScw/MFhYwl5j2u4mli5GDg0VAVeL3RyuQMK+Ai8TqhrlQuxQkXt1Yyw5i cwq4Stzv72AFKRcCqpnfqwgSZhEQkPg2+RDYFAkBWYlNB5hBrpEQOMMmsWHXDyaIMZISB1fc YJnAKLyAkWEVo2hqQXJBcVJ6rpFecWJucWleul5yfu4mRmAAnv73THoH46oGi0OMAhyMSjy8 Cz63BAixJpYVV+YeYpTgYFYS4b0i1hogxJuSWFmVWpQfX1Sak1p8iNEH6JKJzFKiyfnA6Mgr iTc0NjE3NTa1NDIyMzXFIawkztvskRIgJJCeWJKanZpakFoEM46Jg1OqgXGCu9+3yFO7qmz9 /S7/u5m3yte0VSRgid3BN4Kb/jCcjVzn8Y6Hb87yJMl9j7rns/Wc6XGauapkf3NJhN1LuQ2i fX/c482P5fktSuDQnzZX84N95OpL5kc9OcI71rguu8P+vpY9z2f61xsBIT8v81yb2nfi5n6H 50qr5hf/+/pLadOZ7eql4mpKLMUZiYZazEXFiQCvZtmXbQIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupkkeLIzCtJLcpLzFFi42I5/e+xgK6IaWuAweSVFhZTDn9hcWD0uHNt D1sAY1QDo01GamJKapFCal5yfkpmXrqtkndwvHO8qZmBoa6hpYW5kkJeYm6qrZKLT4CuW2YO 0FglhbLEnFKgUEBicbGSvh2mCaEhbroWMI0Rur4hQXA9RgZoIGENY8a2vTdYC97lVZxsmMDY wDgtsouRk0NCwERiaud9NghbTOLCvfVgtpDAIkaJZWdUuxi5QGwmiZtd5xhBEmwCahLrX3eC FYkISEj86r8KFmcWsJFY0nMPzBYWMJeY9ruJpYuRg4NFQFXi90crkDCvgIvE6oa5jBC7FCRe 3VjLDmJzCrhK3O/vYAUpFwKqmd+rOIGRdwEjwypG0dSC5ILipPRcI73ixNzi0rx0veT83E2M 4PB+Jr2DcVWDxSFGAQ5GJR7eBZ9bAoRYE8uKK3MPMUpwMCuJ8F4Raw0Q4k1JrKxKLcqPLyrN SS0+xOgDdNNEZinR5Hxg7OWVxBsam5ibGptamliYmFniEFYS5232SAkQEkhPLEnNTk0tSC2C GcfEwSnVwFg/XSJQcod01eqv0XsKFi17LSOeY6zbduB8nW/Pq++8C5M9TRgnq1Wdv7T7yaa/ Bfl3M+K5ggpbCqob3B7/rtNsb7ihftR7wmS53OY7e5nVKxQWP/4ovyM/zp9hvkB55PSwCfen O054cfF/QnPy7S+MsWcZ1rSev523q+ZDX4zcFm3FP1NyA5VYijMSDbWYi4oTAeKySpacAgAA X-CFilter-Loop: Reflected X-Gm-Message-State: ALoCoQkGlcQ+TKSr/NtFDea154ugUuHwqIrHZDWfT9Kyou3QAC4dACx9szfCqCGKsg2JLk0osw05 From: Rajeshwari Shinde This patch adds SPI driver for EXYNOS. Signed-off-by: Simon Glass Signed-off-by: Padmavathi Venna Signed-off-by: Gabe Black Signed-off-by: Rajeshwari Shinde Signed-off-by: Hatim Ali Acked-by: Mike Frysinger Tested-by: jy0922.shim@samsung.com Acked-by: Simon Glass --- Changes since V4: - Changed SPI bus frequency to 10 Mhz Changes since V5: - Incorporated changes by Minkyu Kang Changes since V6: - No Change diff --git a/arch/arm/include/asm/arch-exynos/spi.h b/arch/arm/include/asm/arch-exynos/spi.h new file mode 100644 index 0000000..7cab1e9 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/spi.h @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Padmavathi Venna + * + * 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 + */ + +#ifndef __ASM_ARCH_EXYNOS_COMMON_SPI_H_ +#define __ASM_ARCH_EXYNOS_COMMON_SPI_H_ + +#ifndef __ASSEMBLY__ + +/* SPI peripheral register map; padded to 64KB */ +struct exynos_spi { + unsigned int ch_cfg; /* 0x00 */ + unsigned char reserved0[4]; + unsigned int mode_cfg; /* 0x08 */ + unsigned int cs_reg; /* 0x0c */ + unsigned char reserved1[4]; + unsigned int spi_sts; /* 0x14 */ + unsigned int tx_data; /* 0x18 */ + unsigned int rx_data; /* 0x1c */ + unsigned int pkt_cnt; /* 0x20 */ + unsigned char reserved2[4]; + unsigned char reserved3[4]; + unsigned int fb_clk; /* 0x2c */ + unsigned char padding[0xffd0]; +}; + +#define EXYNOS_SPI_MAX_FREQ 50000000 + +#define SPI_TIMEOUT_MS 10 + +/* SPI_CHCFG */ +#define SPI_CH_HS_EN (1 << 6) +#define SPI_CH_RST (1 << 5) +#define SPI_SLAVE_MODE (1 << 4) +#define SPI_CH_CPOL_L (1 << 3) +#define SPI_CH_CPHA_B (1 << 2) +#define SPI_RX_CH_ON (1 << 1) +#define SPI_TX_CH_ON (1 << 0) + +/* SPI_MODECFG */ +#define SPI_MODE_CH_WIDTH_WORD (0x2 << 29) +#define SPI_MODE_BUS_WIDTH_WORD (0x2 << 17) + +/* SPI_CSREG */ +#define SPI_SLAVE_SIG_INACT (1 << 0) + +/* SPI_STS */ +#define SPI_ST_TX_DONE (1 << 25) +#define SPI_FIFO_LVL_MASK 0x1ff +#define SPI_TX_LVL_OFFSET 6 +#define SPI_RX_LVL_OFFSET 15 + +/* Feedback Delay */ +#define SPI_CLK_BYPASS (0 << 0) +#define SPI_FB_DELAY_90 (1 << 0) +#define SPI_FB_DELAY_180 (2 << 0) +#define SPI_FB_DELAY_270 (3 << 0) + +/* Packet Count */ +#define SPI_PACKET_CNT_EN (1 << 16) + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f0b82c6..824d357 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -34,6 +34,7 @@ COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o COBJS-$(CONFIG_CF_SPI) += cf_spi.o COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o +COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c new file mode 100644 index 0000000..4ee774b --- /dev/null +++ b/drivers/spi/exynos_spi.c @@ -0,0 +1,366 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Padmavathi Venna + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Information about each SPI controller */ +struct spi_bus { + enum periph_id periph_id; + s32 frequency; /* Default clock frequency, -1 for none */ + struct exynos_spi *regs; + int inited; /* 1 if this bus is ready for use */ +}; + +/* A list of spi buses that we know about */ +static struct spi_bus spi_bus[EXYNOS5_SPI_NUM_CONTROLLERS]; + +struct exynos_spi_slave { + struct spi_slave slave; + struct exynos_spi *regs; + unsigned int freq; /* Default frequency */ + unsigned int mode; + enum periph_id periph_id; /* Peripheral ID for this device */ + unsigned int fifo_size; +}; + +static struct spi_bus *spi_get_bus(unsigned dev_index) +{ + if (dev_index < EXYNOS5_SPI_NUM_CONTROLLERS) + return &spi_bus[dev_index]; + debug("%s: invalid bus %d", __func__, dev_index); + + return NULL; +} + +static inline struct exynos_spi_slave *to_exynos_spi(struct spi_slave *slave) +{ + return container_of(slave, struct exynos_spi_slave, slave); +} + +/** + * Setup the driver private data + * + * @param bus ID of the bus that the slave is attached to + * @param cs ID of the chip select connected to the slave + * @param max_hz Required spi frequency + * @param mode Required spi mode (clk polarity, clk phase and + * master or slave) + * @return new device or NULL + */ +struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct exynos_spi_slave *spi_slave; + struct spi_bus *bus; + + if (!spi_cs_is_valid(busnum, cs)) { + debug("%s: Invalid bus/chip select %d, %d\n", __func__, + busnum, cs); + return NULL; + } + + spi_slave = malloc(sizeof(*spi_slave)); + if (!spi_slave) { + debug("%s: Could not allocate spi_slave\n", __func__); + return NULL; + } + + bus = &spi_bus[busnum]; + spi_slave->slave.bus = busnum; + spi_slave->slave.cs = cs; + spi_slave->regs = bus->regs; + spi_slave->mode = mode; + spi_slave->periph_id = bus->periph_id; + if (bus->periph_id == PERIPH_ID_SPI1 || + bus->periph_id == PERIPH_ID_SPI2) + spi_slave->fifo_size = 64; + else + spi_slave->fifo_size = 256; + + spi_slave->freq = bus->frequency; + if (max_hz) + spi_slave->freq = min(max_hz, spi_slave->freq); + + return &spi_slave->slave; +} + +/** + * Free spi controller + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + */ +void spi_free_slave(struct spi_slave *slave) +{ + struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + + free(spi_slave); +} + +/** + * Flush spi tx, rx fifos and reset the SPI controller + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + */ +static void spi_flush_fifo(struct spi_slave *slave) +{ + struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + struct exynos_spi *regs = spi_slave->regs; + + clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + setbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); +} + +/** + * Initialize the spi base registers, set the required clock frequency and + * initialize the gpios + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + * @return zero on success else a negative value + */ +int spi_claim_bus(struct spi_slave *slave) +{ + struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + struct exynos_spi *regs = spi_slave->regs; + u32 reg = 0; + int ret; + + ret = set_spi_clk(spi_slave->periph_id, + spi_slave->freq); + if (ret < 0) { + debug("%s: Failed to setup spi clock\n", __func__); + return ret; + } + + exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE); + + spi_flush_fifo(slave); + + reg = readl(®s->ch_cfg); + reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L); + + if (spi_slave->mode & SPI_CPHA) + reg |= SPI_CH_CPHA_B; + + if (spi_slave->mode & SPI_CPOL) + reg |= SPI_CH_CPOL_L; + + writel(reg, ®s->ch_cfg); + writel(SPI_FB_DELAY_180, ®s->fb_clk); + + return 0; +} + +/** + * Reset the spi H/W and flush the tx and rx fifos + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + */ +void spi_release_bus(struct spi_slave *slave) +{ + spi_flush_fifo(slave); +} + +static void spi_get_fifo_levels(struct exynos_spi *regs, + int *rx_lvl, int *tx_lvl) +{ + uint32_t spi_sts = readl(®s->spi_sts); + + *rx_lvl = (spi_sts >> SPI_RX_LVL_OFFSET) & SPI_FIFO_LVL_MASK; + *tx_lvl = (spi_sts >> SPI_TX_LVL_OFFSET) & SPI_FIFO_LVL_MASK; +} + +/** + * If there's something to transfer, do a software reset and set a + * transaction size. + * + * @param regs SPI peripheral registers + * @param count Number of bytes to transfer + */ +static void spi_request_bytes(struct exynos_spi *regs, int count) +{ + assert(count && count < (1 << 16)); + setbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + writel(count | SPI_PACKET_CNT_EN, ®s->pkt_cnt); +} + +static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, + void **dinp, void const **doutp) +{ + struct exynos_spi *regs = spi_slave->regs; + uchar *rxp = *dinp; + const uchar *txp = *doutp; + int rx_lvl, tx_lvl; + uint out_bytes, in_bytes; + + out_bytes = in_bytes = todo; + + /* + * If there's something to send, do a software reset and set a + * transaction size. + */ + spi_request_bytes(regs, todo); + + /* + * Bytes are transmitted/received in pairs. Wait to receive all the + * data because then transmission will be done as well. + */ + while (in_bytes) { + int temp; + + /* Keep the fifos full/empty. */ + spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl); + if (tx_lvl < spi_slave->fifo_size && out_bytes) { + temp = txp ? *txp++ : 0xff; + writel(temp, ®s->tx_data); + out_bytes--; + } + if (rx_lvl > 0 && in_bytes) { + temp = readl(®s->rx_data); + if (rxp) + *rxp++ = temp; + in_bytes--; + } + } + *dinp = rxp; + *doutp = txp; +} + +/** + * Transfer and receive data + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + * @param bitlen No of bits to tranfer or receive + * @param dout Pointer to transfer buffer + * @param din Pointer to receive buffer + * @param flags Flags for transfer begin and end + * @return zero on success else a negative value + */ +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + int upto, todo; + int bytelen; + + /* spi core configured to do 8 bit transfers */ + if (bitlen % 8) { + debug("Non byte aligned SPI transfer.\n"); + return -1; + } + + /* Start the transaction, if necessary. */ + if ((flags & SPI_XFER_BEGIN)) + spi_cs_activate(slave); + + /* Exynos SPI limits each transfer to 65535 bytes */ + bytelen = bitlen / 8; + for (upto = 0; upto < bytelen; upto += todo) { + todo = min(bytelen - upto, (1 << 16) - 1); + spi_rx_tx(spi_slave, todo, &din, &dout); + } + + /* Stop the transaction, if necessary. */ + if ((flags & SPI_XFER_END)) + spi_cs_deactivate(slave); + + return 0; +} + +/** + * Validates the bus and chip select numbers + * + * @param bus ID of the bus that the slave is attached to + * @param cs ID of the chip select connected to the slave + * @return one on success else zero + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return spi_get_bus(bus) && cs == 0; +} + +/** + * Activate the CS by driving it LOW + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + */ +void spi_cs_activate(struct spi_slave *slave) +{ + struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + + clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); + debug("Activate CS, bus %d\n", spi_slave->slave.bus); +} + +/** + * Deactivate the CS by driving it HIGH + * + * @param slave Pointer to spi_slave to which controller has to + * communicate with + */ +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + + setbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); + debug("Deactivate CS, bus %d\n", spi_slave->slave.bus); +} + +static inline struct exynos_spi *get_spi_base(int dev_index) +{ + if (dev_index < 3) + return (struct exynos_spi *)samsung_get_base_spi() + dev_index; + else + return (struct exynos_spi *)samsung_get_base_spi_isp() + + (dev_index - 3); +} + +/* Sadly there is no error return from this function */ +void spi_init(void) +{ + int i; + struct spi_bus *bus; + for (i = 0; i < EXYNOS5_SPI_NUM_CONTROLLERS; i++) { + bus = &spi_bus[i]; + bus->regs = get_spi_base(i); + bus->periph_id = PERIPH_ID_SPI0 + i; + + /* Although Exynos5 supports upto 50Mhz speed, + * we are setting it to 10Mhz for safe side + */ + bus->frequency = 10000000; + bus->inited = 1; + } +}