Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anders Berg and committed by
Mark Brown
db4fa45e 73e3f1eb

+63 -1
+58 -1
drivers/spi/spi-pl022.c
··· 82 82 #define SSP_MIS(r) (r + 0x01C) 83 83 #define SSP_ICR(r) (r + 0x020) 84 84 #define SSP_DMACR(r) (r + 0x024) 85 + #define SSP_CSR(r) (r + 0x030) /* vendor extension */ 85 86 #define SSP_ITCR(r) (r + 0x080) 86 87 #define SSP_ITIP(r) (r + 0x084) 87 88 #define SSP_ITOP(r) (r + 0x088) ··· 197 196 #define SSP_DMACR_MASK_RXDMAE (0x1UL << 0) 198 197 /* Transmit DMA Enable bit */ 199 198 #define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) 199 + 200 + /* 201 + * SSP Chip Select Control Register - SSP_CSR 202 + * (vendor extension) 203 + */ 204 + #define SSP_CSR_CSVALUE_MASK (0x1FUL << 0) 200 205 201 206 /* 202 207 * SSP Integration Test control Register - SSP_ITCR ··· 320 313 * @extended_cr: 32 bit wide control register 0 with extra 321 314 * features and extra features in CR1 as found in the ST variants 322 315 * @pl023: supports a subset of the ST extensions called "PL023" 316 + * @internal_cs_ctrl: supports chip select control register 323 317 */ 324 318 struct vendor_data { 325 319 int fifodepth; ··· 329 321 bool extended_cr; 330 322 bool pl023; 331 323 bool loopback; 324 + bool internal_cs_ctrl; 332 325 }; 333 326 334 327 /** ··· 449 440 pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); 450 441 } 451 442 443 + /** 444 + * internal_cs_control - Control chip select signals via SSP_CSR. 445 + * @pl022: SSP driver private data structure 446 + * @command: select/delect the chip 447 + * 448 + * Used on controller with internal chip select control via SSP_CSR register 449 + * (vendor extension). Each of the 5 LSB in the register controls one chip 450 + * select signal. 451 + */ 452 + static void internal_cs_control(struct pl022 *pl022, u32 command) 453 + { 454 + u32 tmp; 455 + 456 + tmp = readw(SSP_CSR(pl022->virtbase)); 457 + if (command == SSP_CHIP_SELECT) 458 + tmp &= ~BIT(pl022->cur_cs); 459 + else 460 + tmp |= BIT(pl022->cur_cs); 461 + writew(tmp, SSP_CSR(pl022->virtbase)); 462 + } 463 + 452 464 static void pl022_cs_control(struct pl022 *pl022, u32 command) 453 465 { 454 - if (gpio_is_valid(pl022->cur_cs)) 466 + if (pl022->vendor->internal_cs_ctrl) 467 + internal_cs_control(pl022, command); 468 + else if (gpio_is_valid(pl022->cur_cs)) 455 469 gpio_set_value(pl022->cur_cs, command); 456 470 else 457 471 pl022->cur_chip->cs_control(command); ··· 2154 2122 if (platform_info->num_chipselect && platform_info->chipselects) { 2155 2123 for (i = 0; i < num_cs; i++) 2156 2124 pl022->chipselects[i] = platform_info->chipselects[i]; 2125 + } else if (pl022->vendor->internal_cs_ctrl) { 2126 + for (i = 0; i < num_cs; i++) 2127 + pl022->chipselects[i] = i; 2157 2128 } else if (IS_ENABLED(CONFIG_OF)) { 2158 2129 for (i = 0; i < num_cs; i++) { 2159 2130 int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); ··· 2387 2352 .extended_cr = false, 2388 2353 .pl023 = false, 2389 2354 .loopback = true, 2355 + .internal_cs_ctrl = false, 2390 2356 }; 2391 2357 2392 2358 static struct vendor_data vendor_st = { ··· 2397 2361 .extended_cr = true, 2398 2362 .pl023 = false, 2399 2363 .loopback = true, 2364 + .internal_cs_ctrl = false, 2400 2365 }; 2401 2366 2402 2367 static struct vendor_data vendor_st_pl023 = { ··· 2407 2370 .extended_cr = true, 2408 2371 .pl023 = true, 2409 2372 .loopback = false, 2373 + .internal_cs_ctrl = false, 2374 + }; 2375 + 2376 + static struct vendor_data vendor_lsi = { 2377 + .fifodepth = 8, 2378 + .max_bpw = 16, 2379 + .unidir = false, 2380 + .extended_cr = false, 2381 + .pl023 = false, 2382 + .loopback = true, 2383 + .internal_cs_ctrl = true, 2410 2384 }; 2411 2385 2412 2386 static struct amba_id pl022_ids[] = { ··· 2450 2402 .id = 0x00080023, 2451 2403 .mask = 0xffffffff, 2452 2404 .data = &vendor_st_pl023, 2405 + }, 2406 + { 2407 + /* 2408 + * PL022 variant that has a chip select control register whih 2409 + * allows control of 5 output signals nCS[0:4]. 2410 + */ 2411 + .id = 0x000b6022, 2412 + .mask = 0x000fffff, 2413 + .data = &vendor_lsi, 2453 2414 }, 2454 2415 { 0, 0 }, 2455 2416 };
+5
include/linux/amba/bus.h
··· 44 44 const struct amba_id *id_table; 45 45 }; 46 46 47 + /* 48 + * Constants for the designer field of the Peripheral ID register. When bit 7 49 + * is set to '1', bits [6:0] should be the JEP106 manufacturer identity code. 50 + */ 47 51 enum amba_vendor { 48 52 AMBA_VENDOR_ARM = 0x41, 49 53 AMBA_VENDOR_ST = 0x80, 50 54 AMBA_VENDOR_QCOM = 0x51, 55 + AMBA_VENDOR_LSI = 0xb6, 51 56 }; 52 57 53 58 extern struct bus_type amba_bustype;