| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 1 | /* linux/arch/arm/plat-s3c64xx/dev-spi.c | 
|  | 2 | * | 
|  | 3 | * Copyright (C) 2009 Samsung Electronics 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/kernel.h> | 
|  | 12 | #include <linux/string.h> | 
|  | 13 | #include <linux/platform_device.h> | 
|  | 14 | #include <linux/dma-mapping.h> | 
| Kukjin Kim | 1c739c7 | 2010-08-05 07:54:49 +0900 | [diff] [blame] | 15 | #include <linux/gpio.h> | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 16 |  | 
|  | 17 | #include <mach/dma.h> | 
|  | 18 | #include <mach/map.h> | 
| Ben Dooks | 88fc68a | 2010-01-26 11:19:18 +0900 | [diff] [blame] | 19 | #include <mach/spi-clocks.h> | 
| Mark Brown | 23a07eb | 2010-09-09 11:12:37 +0900 | [diff] [blame] | 20 | #include <mach/irqs.h> | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 21 |  | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 22 | #include <plat/s3c64xx-spi.h> | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 23 | #include <plat/gpio-cfg.h> | 
| Mark Brown | 5343795 | 2010-09-18 09:54:38 +0900 | [diff] [blame] | 24 | #include <plat/devs.h> | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 25 |  | 
|  | 26 | static char *spi_src_clks[] = { | 
|  | 27 | [S3C64XX_SPI_SRCCLK_PCLK] = "pclk", | 
|  | 28 | [S3C64XX_SPI_SRCCLK_SPIBUS] = "spi-bus", | 
|  | 29 | [S3C64XX_SPI_SRCCLK_48M] = "spi_48m", | 
|  | 30 | }; | 
|  | 31 |  | 
|  | 32 | /* SPI Controller platform_devices */ | 
|  | 33 |  | 
|  | 34 | /* Since we emulate multi-cs capability, we do not touch the GPC-3,7. | 
|  | 35 | * The emulated CS is toggled by board specific mechanism, as it can | 
|  | 36 | * be either some immediate GPIO or some signal out of some other | 
|  | 37 | * chip in between ... or some yet another way. | 
|  | 38 | * We simply do not assume anything about CS. | 
|  | 39 | */ | 
|  | 40 | static int s3c64xx_spi_cfg_gpio(struct platform_device *pdev) | 
|  | 41 | { | 
| Joonyoung Shim | 3185847 | 2011-05-06 09:37:17 +0900 | [diff] [blame] | 42 | unsigned int base; | 
|  | 43 |  | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 44 | switch (pdev->id) { | 
|  | 45 | case 0: | 
| Joonyoung Shim | 3185847 | 2011-05-06 09:37:17 +0900 | [diff] [blame] | 46 | base = S3C64XX_GPC(0); | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 47 | break; | 
|  | 48 |  | 
|  | 49 | case 1: | 
| Joonyoung Shim | 3185847 | 2011-05-06 09:37:17 +0900 | [diff] [blame] | 50 | base = S3C64XX_GPC(4); | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 51 | break; | 
|  | 52 |  | 
|  | 53 | default: | 
|  | 54 | dev_err(&pdev->dev, "Invalid SPI Controller number!"); | 
|  | 55 | return -EINVAL; | 
|  | 56 | } | 
|  | 57 |  | 
| Joonyoung Shim | 3185847 | 2011-05-06 09:37:17 +0900 | [diff] [blame] | 58 | s3c_gpio_cfgall_range(base, 3, | 
|  | 59 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); | 
|  | 60 |  | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 61 | return 0; | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | static struct resource s3c64xx_spi0_resource[] = { | 
|  | 65 | [0] = { | 
|  | 66 | .start = S3C64XX_PA_SPI0, | 
|  | 67 | .end   = S3C64XX_PA_SPI0 + 0x100 - 1, | 
|  | 68 | .flags = IORESOURCE_MEM, | 
|  | 69 | }, | 
|  | 70 | [1] = { | 
|  | 71 | .start = DMACH_SPI0_TX, | 
|  | 72 | .end   = DMACH_SPI0_TX, | 
|  | 73 | .flags = IORESOURCE_DMA, | 
|  | 74 | }, | 
|  | 75 | [2] = { | 
|  | 76 | .start = DMACH_SPI0_RX, | 
|  | 77 | .end   = DMACH_SPI0_RX, | 
|  | 78 | .flags = IORESOURCE_DMA, | 
|  | 79 | }, | 
|  | 80 | [3] = { | 
|  | 81 | .start = IRQ_SPI0, | 
|  | 82 | .end   = IRQ_SPI0, | 
|  | 83 | .flags = IORESOURCE_IRQ, | 
|  | 84 | }, | 
|  | 85 | }; | 
|  | 86 |  | 
|  | 87 | static struct s3c64xx_spi_info s3c64xx_spi0_pdata = { | 
|  | 88 | .cfg_gpio = s3c64xx_spi_cfg_gpio, | 
|  | 89 | .fifo_lvl_mask = 0x7f, | 
|  | 90 | .rx_lvl_offset = 13, | 
|  | 91 | }; | 
|  | 92 |  | 
|  | 93 | static u64 spi_dmamask = DMA_BIT_MASK(32); | 
|  | 94 |  | 
|  | 95 | struct platform_device s3c64xx_device_spi0 = { | 
|  | 96 | .name		  = "s3c64xx-spi", | 
|  | 97 | .id		  = 0, | 
|  | 98 | .num_resources	  = ARRAY_SIZE(s3c64xx_spi0_resource), | 
|  | 99 | .resource	  = s3c64xx_spi0_resource, | 
|  | 100 | .dev = { | 
|  | 101 | .dma_mask		= &spi_dmamask, | 
|  | 102 | .coherent_dma_mask	= DMA_BIT_MASK(32), | 
|  | 103 | .platform_data = &s3c64xx_spi0_pdata, | 
|  | 104 | }, | 
|  | 105 | }; | 
|  | 106 | EXPORT_SYMBOL(s3c64xx_device_spi0); | 
|  | 107 |  | 
|  | 108 | static struct resource s3c64xx_spi1_resource[] = { | 
|  | 109 | [0] = { | 
|  | 110 | .start = S3C64XX_PA_SPI1, | 
|  | 111 | .end   = S3C64XX_PA_SPI1 + 0x100 - 1, | 
|  | 112 | .flags = IORESOURCE_MEM, | 
|  | 113 | }, | 
|  | 114 | [1] = { | 
|  | 115 | .start = DMACH_SPI1_TX, | 
|  | 116 | .end   = DMACH_SPI1_TX, | 
|  | 117 | .flags = IORESOURCE_DMA, | 
|  | 118 | }, | 
|  | 119 | [2] = { | 
|  | 120 | .start = DMACH_SPI1_RX, | 
|  | 121 | .end   = DMACH_SPI1_RX, | 
|  | 122 | .flags = IORESOURCE_DMA, | 
|  | 123 | }, | 
|  | 124 | [3] = { | 
|  | 125 | .start = IRQ_SPI1, | 
|  | 126 | .end   = IRQ_SPI1, | 
|  | 127 | .flags = IORESOURCE_IRQ, | 
|  | 128 | }, | 
|  | 129 | }; | 
|  | 130 |  | 
|  | 131 | static struct s3c64xx_spi_info s3c64xx_spi1_pdata = { | 
|  | 132 | .cfg_gpio = s3c64xx_spi_cfg_gpio, | 
|  | 133 | .fifo_lvl_mask = 0x7f, | 
|  | 134 | .rx_lvl_offset = 13, | 
|  | 135 | }; | 
|  | 136 |  | 
|  | 137 | struct platform_device s3c64xx_device_spi1 = { | 
|  | 138 | .name		  = "s3c64xx-spi", | 
|  | 139 | .id		  = 1, | 
|  | 140 | .num_resources	  = ARRAY_SIZE(s3c64xx_spi1_resource), | 
|  | 141 | .resource	  = s3c64xx_spi1_resource, | 
|  | 142 | .dev = { | 
|  | 143 | .dma_mask		= &spi_dmamask, | 
|  | 144 | .coherent_dma_mask	= DMA_BIT_MASK(32), | 
|  | 145 | .platform_data = &s3c64xx_spi1_pdata, | 
|  | 146 | }, | 
|  | 147 | }; | 
|  | 148 | EXPORT_SYMBOL(s3c64xx_device_spi1); | 
|  | 149 |  | 
|  | 150 | void __init s3c64xx_spi_set_info(int cntrlr, int src_clk_nr, int num_cs) | 
|  | 151 | { | 
| Ben Dooks | 75497d9 | 2010-01-21 13:31:38 +0900 | [diff] [blame] | 152 | struct s3c64xx_spi_info *pd; | 
|  | 153 |  | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 154 | /* Reject invalid configuration */ | 
|  | 155 | if (!num_cs || src_clk_nr < 0 | 
|  | 156 | || src_clk_nr > S3C64XX_SPI_SRCCLK_48M) { | 
|  | 157 | printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__); | 
|  | 158 | return; | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | switch (cntrlr) { | 
|  | 162 | case 0: | 
| Ben Dooks | 75497d9 | 2010-01-21 13:31:38 +0900 | [diff] [blame] | 163 | pd = &s3c64xx_spi0_pdata; | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 164 | break; | 
|  | 165 | case 1: | 
| Ben Dooks | 75497d9 | 2010-01-21 13:31:38 +0900 | [diff] [blame] | 166 | pd = &s3c64xx_spi1_pdata; | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 167 | break; | 
|  | 168 | default: | 
|  | 169 | printk(KERN_ERR "%s: Invalid SPI controller(%d)\n", | 
|  | 170 | __func__, cntrlr); | 
|  | 171 | return; | 
|  | 172 | } | 
| Ben Dooks | 75497d9 | 2010-01-21 13:31:38 +0900 | [diff] [blame] | 173 |  | 
|  | 174 | pd->num_cs = num_cs; | 
|  | 175 | pd->src_clk_nr = src_clk_nr; | 
|  | 176 | pd->src_clk_name = spi_src_clks[src_clk_nr]; | 
| Jassi Brar | 6a2b411 | 2010-01-18 17:32:02 +0900 | [diff] [blame] | 177 | } |