1/* linux/arch/arm/mach-s5pc100/dev-spi.c 2 * 3 * Copyright (C) 2010 Samsung Electronics Co. Ltd. 4 * Jaswinder Singh <jassi.brar@samsung.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11#include <linux/platform_device.h> 12#include <linux/dma-mapping.h> 13#include <linux/gpio.h> 14 15#include <mach/dma.h> 16#include <mach/map.h> 17#include <mach/spi-clocks.h> 18 19#include <plat/s3c64xx-spi.h> 20#include <plat/gpio-cfg.h> 21#include <plat/irqs.h> 22 23static char *spi_src_clks[] = { 24 [S5PC100_SPI_SRCCLK_PCLK] = "pclk", 25 [S5PC100_SPI_SRCCLK_48M] = "spi_48m", 26 [S5PC100_SPI_SRCCLK_SPIBUS] = "spi_bus", 27}; 28 29/* SPI Controller platform_devices */ 30 31/* Since we emulate multi-cs capability, we do not touch the CS. 32 * The emulated CS is toggled by board specific mechanism, as it can 33 * be either some immediate GPIO or some signal out of some other 34 * chip in between ... or some yet another way. 35 * We simply do not assume anything about CS. 36 */ 37static int s5pc100_spi_cfg_gpio(struct platform_device *pdev) 38{ 39 switch (pdev->id) { 40 case 0: 41 s3c_gpio_cfgpin(S5PC100_GPB(0), S3C_GPIO_SFN(2)); 42 s3c_gpio_cfgpin(S5PC100_GPB(1), S3C_GPIO_SFN(2)); 43 s3c_gpio_cfgpin(S5PC100_GPB(2), S3C_GPIO_SFN(2)); 44 s3c_gpio_setpull(S5PC100_GPB(0), S3C_GPIO_PULL_UP); 45 s3c_gpio_setpull(S5PC100_GPB(1), S3C_GPIO_PULL_UP); 46 s3c_gpio_setpull(S5PC100_GPB(2), S3C_GPIO_PULL_UP); 47 break; 48 49 case 1: 50 s3c_gpio_cfgpin(S5PC100_GPB(4), S3C_GPIO_SFN(2)); 51 s3c_gpio_cfgpin(S5PC100_GPB(5), S3C_GPIO_SFN(2)); 52 s3c_gpio_cfgpin(S5PC100_GPB(6), S3C_GPIO_SFN(2)); 53 s3c_gpio_setpull(S5PC100_GPB(4), S3C_GPIO_PULL_UP); 54 s3c_gpio_setpull(S5PC100_GPB(5), S3C_GPIO_PULL_UP); 55 s3c_gpio_setpull(S5PC100_GPB(6), S3C_GPIO_PULL_UP); 56 break; 57 58 case 2: 59 s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(3)); 60 s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(3)); 61 s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(3)); 62 s3c_gpio_setpull(S5PC100_GPG3(0), S3C_GPIO_PULL_UP); 63 s3c_gpio_setpull(S5PC100_GPG3(2), S3C_GPIO_PULL_UP); 64 s3c_gpio_setpull(S5PC100_GPG3(3), S3C_GPIO_PULL_UP); 65 break; 66 67 default: 68 dev_err(&pdev->dev, "Invalid SPI Controller number!"); 69 return -EINVAL; 70 } 71 72 return 0; 73} 74 75static struct resource s5pc100_spi0_resource[] = { 76 [0] = { 77 .start = S5PC100_PA_SPI0, 78 .end = S5PC100_PA_SPI0 + 0x100 - 1, 79 .flags = IORESOURCE_MEM, 80 }, 81 [1] = { 82 .start = DMACH_SPI0_TX, 83 .end = DMACH_SPI0_TX, 84 .flags = IORESOURCE_DMA, 85 }, 86 [2] = { 87 .start = DMACH_SPI0_RX, 88 .end = DMACH_SPI0_RX, 89 .flags = IORESOURCE_DMA, 90 }, 91 [3] = { 92 .start = IRQ_SPI0, 93 .end = IRQ_SPI0, 94 .flags = IORESOURCE_IRQ, 95 }, 96}; 97 98static struct s3c64xx_spi_info s5pc100_spi0_pdata = { 99 .cfg_gpio = s5pc100_spi_cfg_gpio, 100 .fifo_lvl_mask = 0x7f, 101 .rx_lvl_offset = 13, 102 .high_speed = 1, 103}; 104 105static u64 spi_dmamask = DMA_BIT_MASK(32); 106 107struct platform_device s5pc100_device_spi0 = { 108 .name = "s3c64xx-spi", 109 .id = 0, 110 .num_resources = ARRAY_SIZE(s5pc100_spi0_resource), 111 .resource = s5pc100_spi0_resource, 112 .dev = { 113 .dma_mask = &spi_dmamask, 114 .coherent_dma_mask = DMA_BIT_MASK(32), 115 .platform_data = &s5pc100_spi0_pdata, 116 }, 117}; 118 119static struct resource s5pc100_spi1_resource[] = { 120 [0] = { 121 .start = S5PC100_PA_SPI1, 122 .end = S5PC100_PA_SPI1 + 0x100 - 1, 123 .flags = IORESOURCE_MEM, 124 }, 125 [1] = { 126 .start = DMACH_SPI1_TX, 127 .end = DMACH_SPI1_TX, 128 .flags = IORESOURCE_DMA, 129 }, 130 [2] = { 131 .start = DMACH_SPI1_RX, 132 .end = DMACH_SPI1_RX, 133 .flags = IORESOURCE_DMA, 134 }, 135 [3] = { 136 .start = IRQ_SPI1, 137 .end = IRQ_SPI1, 138 .flags = IORESOURCE_IRQ, 139 }, 140}; 141 142static struct s3c64xx_spi_info s5pc100_spi1_pdata = { 143 .cfg_gpio = s5pc100_spi_cfg_gpio, 144 .fifo_lvl_mask = 0x7f, 145 .rx_lvl_offset = 13, 146 .high_speed = 1, 147}; 148 149struct platform_device s5pc100_device_spi1 = { 150 .name = "s3c64xx-spi", 151 .id = 1, 152 .num_resources = ARRAY_SIZE(s5pc100_spi1_resource), 153 .resource = s5pc100_spi1_resource, 154 .dev = { 155 .dma_mask = &spi_dmamask, 156 .coherent_dma_mask = DMA_BIT_MASK(32), 157 .platform_data = &s5pc100_spi1_pdata, 158 }, 159}; 160 161static struct resource s5pc100_spi2_resource[] = { 162 [0] = { 163 .start = S5PC100_PA_SPI2, 164 .end = S5PC100_PA_SPI2 + 0x100 - 1, 165 .flags = IORESOURCE_MEM, 166 }, 167 [1] = { 168 .start = DMACH_SPI2_TX, 169 .end = DMACH_SPI2_TX, 170 .flags = IORESOURCE_DMA, 171 }, 172 [2] = { 173 .start = DMACH_SPI2_RX, 174 .end = DMACH_SPI2_RX, 175 .flags = IORESOURCE_DMA, 176 }, 177 [3] = { 178 .start = IRQ_SPI2, 179 .end = IRQ_SPI2, 180 .flags = IORESOURCE_IRQ, 181 }, 182}; 183 184static struct s3c64xx_spi_info s5pc100_spi2_pdata = { 185 .cfg_gpio = s5pc100_spi_cfg_gpio, 186 .fifo_lvl_mask = 0x7f, 187 .rx_lvl_offset = 13, 188 .high_speed = 1, 189}; 190 191struct platform_device s5pc100_device_spi2 = { 192 .name = "s3c64xx-spi", 193 .id = 2, 194 .num_resources = ARRAY_SIZE(s5pc100_spi2_resource), 195 .resource = s5pc100_spi2_resource, 196 .dev = { 197 .dma_mask = &spi_dmamask, 198 .coherent_dma_mask = DMA_BIT_MASK(32), 199 .platform_data = &s5pc100_spi2_pdata, 200 }, 201}; 202 203void __init s5pc100_spi_set_info(int cntrlr, int src_clk_nr, int num_cs) 204{ 205 struct s3c64xx_spi_info *pd; 206 207 /* Reject invalid configuration */ 208 if (!num_cs || src_clk_nr < 0 209 || src_clk_nr > S5PC100_SPI_SRCCLK_SPIBUS) { 210 printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__); 211 return; 212 } 213 214 switch (cntrlr) { 215 case 0: 216 pd = &s5pc100_spi0_pdata; 217 break; 218 case 1: 219 pd = &s5pc100_spi1_pdata; 220 break; 221 case 2: 222 pd = &s5pc100_spi2_pdata; 223 break; 224 default: 225 printk(KERN_ERR "%s: Invalid SPI controller(%d)\n", 226 __func__, cntrlr); 227 return; 228 } 229 230 pd->num_cs = num_cs; 231 pd->src_clk_nr = src_clk_nr; 232 pd->src_clk_name = spi_src_clks[src_clk_nr]; 233} 234