aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorAnders Berg <anders.berg@avagotech.com>2014-09-17 02:46:58 -0400
committerMark Brown <broonie@kernel.org>2014-09-24 05:25:52 -0400
commitdb4fa45ed3182d8206af241811dfc99369ffa849 (patch)
tree3da0916f874df0cdb7def2e724cf6f32958b30ce /drivers/spi
parent73e3f1eb51888303389f2dc2219c97ce34ca6db0 (diff)
spi: pl022: Add support for chip select extension
Add support for a extended PL022 which has an extra register for controlling up to five chip select signals. This controller is found on the AXM5516 SoC. Unfortunately the PrimeCell identification registers are identical to a standard ARM PL022. To work around this, the peripheral ID must be overridden in the device tree using the "arm,primecell-periphid" property with the value 0x000b6022. Signed-off-by: Anders Berg <anders.berg@avagotech.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-pl022.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 7f13f3f7198b..d0741b2eabb4 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -82,6 +82,7 @@
82#define SSP_MIS(r) (r + 0x01C) 82#define SSP_MIS(r) (r + 0x01C)
83#define SSP_ICR(r) (r + 0x020) 83#define SSP_ICR(r) (r + 0x020)
84#define SSP_DMACR(r) (r + 0x024) 84#define SSP_DMACR(r) (r + 0x024)
85#define SSP_CSR(r) (r + 0x030) /* vendor extension */
85#define SSP_ITCR(r) (r + 0x080) 86#define SSP_ITCR(r) (r + 0x080)
86#define SSP_ITIP(r) (r + 0x084) 87#define SSP_ITIP(r) (r + 0x084)
87#define SSP_ITOP(r) (r + 0x088) 88#define SSP_ITOP(r) (r + 0x088)
@@ -198,6 +199,12 @@
198#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) 199#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1)
199 200
200/* 201/*
202 * SSP Chip Select Control Register - SSP_CSR
203 * (vendor extension)
204 */
205#define SSP_CSR_CSVALUE_MASK (0x1FUL << 0)
206
207/*
201 * SSP Integration Test control Register - SSP_ITCR 208 * SSP Integration Test control Register - SSP_ITCR
202 */ 209 */
203#define SSP_ITCR_MASK_ITEN (0x1UL << 0) 210#define SSP_ITCR_MASK_ITEN (0x1UL << 0)
@@ -313,6 +320,7 @@ enum ssp_writing {
313 * @extended_cr: 32 bit wide control register 0 with extra 320 * @extended_cr: 32 bit wide control register 0 with extra
314 * features and extra features in CR1 as found in the ST variants 321 * features and extra features in CR1 as found in the ST variants
315 * @pl023: supports a subset of the ST extensions called "PL023" 322 * @pl023: supports a subset of the ST extensions called "PL023"
323 * @internal_cs_ctrl: supports chip select control register
316 */ 324 */
317struct vendor_data { 325struct vendor_data {
318 int fifodepth; 326 int fifodepth;
@@ -321,6 +329,7 @@ struct vendor_data {
321 bool extended_cr; 329 bool extended_cr;
322 bool pl023; 330 bool pl023;
323 bool loopback; 331 bool loopback;
332 bool internal_cs_ctrl;
324}; 333};
325 334
326/** 335/**
@@ -440,9 +449,32 @@ static void null_cs_control(u32 command)
440 pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); 449 pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
441} 450}
442 451
452/**
453 * internal_cs_control - Control chip select signals via SSP_CSR.
454 * @pl022: SSP driver private data structure
455 * @command: select/delect the chip
456 *
457 * Used on controller with internal chip select control via SSP_CSR register
458 * (vendor extension). Each of the 5 LSB in the register controls one chip
459 * select signal.
460 */
461static void internal_cs_control(struct pl022 *pl022, u32 command)
462{
463 u32 tmp;
464
465 tmp = readw(SSP_CSR(pl022->virtbase));
466 if (command == SSP_CHIP_SELECT)
467 tmp &= ~BIT(pl022->cur_cs);
468 else
469 tmp |= BIT(pl022->cur_cs);
470 writew(tmp, SSP_CSR(pl022->virtbase));
471}
472
443static void pl022_cs_control(struct pl022 *pl022, u32 command) 473static void pl022_cs_control(struct pl022 *pl022, u32 command)
444{ 474{
445 if (gpio_is_valid(pl022->cur_cs)) 475 if (pl022->vendor->internal_cs_ctrl)
476 internal_cs_control(pl022, command);
477 else if (gpio_is_valid(pl022->cur_cs))
446 gpio_set_value(pl022->cur_cs, command); 478 gpio_set_value(pl022->cur_cs, command);
447 else 479 else
448 pl022->cur_chip->cs_control(command); 480 pl022->cur_chip->cs_control(command);
@@ -2122,6 +2154,9 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
2122 if (platform_info->num_chipselect && platform_info->chipselects) { 2154 if (platform_info->num_chipselect && platform_info->chipselects) {
2123 for (i = 0; i < num_cs; i++) 2155 for (i = 0; i < num_cs; i++)
2124 pl022->chipselects[i] = platform_info->chipselects[i]; 2156 pl022->chipselects[i] = platform_info->chipselects[i];
2157 } else if (pl022->vendor->internal_cs_ctrl) {
2158 for (i = 0; i < num_cs; i++)
2159 pl022->chipselects[i] = i;
2125 } else if (IS_ENABLED(CONFIG_OF)) { 2160 } else if (IS_ENABLED(CONFIG_OF)) {
2126 for (i = 0; i < num_cs; i++) { 2161 for (i = 0; i < num_cs; i++) {
2127 int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); 2162 int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
@@ -2352,6 +2387,7 @@ static struct vendor_data vendor_arm = {
2352 .extended_cr = false, 2387 .extended_cr = false,
2353 .pl023 = false, 2388 .pl023 = false,
2354 .loopback = true, 2389 .loopback = true,
2390 .internal_cs_ctrl = false,
2355}; 2391};
2356 2392
2357static struct vendor_data vendor_st = { 2393static struct vendor_data vendor_st = {
@@ -2361,6 +2397,7 @@ static struct vendor_data vendor_st = {
2361 .extended_cr = true, 2397 .extended_cr = true,
2362 .pl023 = false, 2398 .pl023 = false,
2363 .loopback = true, 2399 .loopback = true,
2400 .internal_cs_ctrl = false,
2364}; 2401};
2365 2402
2366static struct vendor_data vendor_st_pl023 = { 2403static struct vendor_data vendor_st_pl023 = {
@@ -2370,6 +2407,17 @@ static struct vendor_data vendor_st_pl023 = {
2370 .extended_cr = true, 2407 .extended_cr = true,
2371 .pl023 = true, 2408 .pl023 = true,
2372 .loopback = false, 2409 .loopback = false,
2410 .internal_cs_ctrl = false,
2411};
2412
2413static struct vendor_data vendor_lsi = {
2414 .fifodepth = 8,
2415 .max_bpw = 16,
2416 .unidir = false,
2417 .extended_cr = false,
2418 .pl023 = false,
2419 .loopback = true,
2420 .internal_cs_ctrl = true,
2373}; 2421};
2374 2422
2375static struct amba_id pl022_ids[] = { 2423static struct amba_id pl022_ids[] = {
@@ -2403,6 +2451,15 @@ static struct amba_id pl022_ids[] = {
2403 .mask = 0xffffffff, 2451 .mask = 0xffffffff,
2404 .data = &vendor_st_pl023, 2452 .data = &vendor_st_pl023,
2405 }, 2453 },
2454 {
2455 /*
2456 * PL022 variant that has a chip select control register whih
2457 * allows control of 5 output signals nCS[0:4].
2458 */
2459 .id = 0x000b6022,
2460 .mask = 0x000fffff,
2461 .data = &vendor_lsi,
2462 },
2406 { 0, 0 }, 2463 { 0, 0 },
2407}; 2464};
2408 2465