diff options
Diffstat (limited to 'drivers/spi/spi-pl022.c')
-rw-r--r-- | drivers/spi/spi-pl022.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index f1f0a587e4fc..f35f723816ea 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 | */ |
317 | struct vendor_data { | 325 | struct 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 | */ | ||
461 | static 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 | |||
443 | static void pl022_cs_control(struct pl022 *pl022, u32 command) | 473 | static 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); |
@@ -2100,6 +2132,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2100 | pl022->vendor = id->data; | 2132 | pl022->vendor = id->data; |
2101 | pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), | 2133 | pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), |
2102 | GFP_KERNEL); | 2134 | GFP_KERNEL); |
2135 | if (!pl022->chipselects) { | ||
2136 | status = -ENOMEM; | ||
2137 | goto err_no_mem; | ||
2138 | } | ||
2103 | 2139 | ||
2104 | /* | 2140 | /* |
2105 | * Bus Number Which has been Assigned to this SSP controller | 2141 | * Bus Number Which has been Assigned to this SSP controller |
@@ -2118,6 +2154,9 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2118 | if (platform_info->num_chipselect && platform_info->chipselects) { | 2154 | if (platform_info->num_chipselect && platform_info->chipselects) { |
2119 | for (i = 0; i < num_cs; i++) | 2155 | for (i = 0; i < num_cs; i++) |
2120 | 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; | ||
2121 | } else if (IS_ENABLED(CONFIG_OF)) { | 2160 | } else if (IS_ENABLED(CONFIG_OF)) { |
2122 | for (i = 0; i < num_cs; i++) { | 2161 | for (i = 0; i < num_cs; i++) { |
2123 | int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); | 2162 | int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); |
@@ -2241,6 +2280,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2241 | amba_release_regions(adev); | 2280 | amba_release_regions(adev); |
2242 | err_no_ioregion: | 2281 | err_no_ioregion: |
2243 | err_no_gpio: | 2282 | err_no_gpio: |
2283 | err_no_mem: | ||
2244 | spi_master_put(master); | 2284 | spi_master_put(master); |
2245 | return status; | 2285 | return status; |
2246 | } | 2286 | } |
@@ -2347,6 +2387,7 @@ static struct vendor_data vendor_arm = { | |||
2347 | .extended_cr = false, | 2387 | .extended_cr = false, |
2348 | .pl023 = false, | 2388 | .pl023 = false, |
2349 | .loopback = true, | 2389 | .loopback = true, |
2390 | .internal_cs_ctrl = false, | ||
2350 | }; | 2391 | }; |
2351 | 2392 | ||
2352 | static struct vendor_data vendor_st = { | 2393 | static struct vendor_data vendor_st = { |
@@ -2356,6 +2397,7 @@ static struct vendor_data vendor_st = { | |||
2356 | .extended_cr = true, | 2397 | .extended_cr = true, |
2357 | .pl023 = false, | 2398 | .pl023 = false, |
2358 | .loopback = true, | 2399 | .loopback = true, |
2400 | .internal_cs_ctrl = false, | ||
2359 | }; | 2401 | }; |
2360 | 2402 | ||
2361 | static struct vendor_data vendor_st_pl023 = { | 2403 | static struct vendor_data vendor_st_pl023 = { |
@@ -2365,6 +2407,17 @@ static struct vendor_data vendor_st_pl023 = { | |||
2365 | .extended_cr = true, | 2407 | .extended_cr = true, |
2366 | .pl023 = true, | 2408 | .pl023 = true, |
2367 | .loopback = false, | 2409 | .loopback = false, |
2410 | .internal_cs_ctrl = false, | ||
2411 | }; | ||
2412 | |||
2413 | static 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, | ||
2368 | }; | 2421 | }; |
2369 | 2422 | ||
2370 | static struct amba_id pl022_ids[] = { | 2423 | static struct amba_id pl022_ids[] = { |
@@ -2398,6 +2451,15 @@ static struct amba_id pl022_ids[] = { | |||
2398 | .mask = 0xffffffff, | 2451 | .mask = 0xffffffff, |
2399 | .data = &vendor_st_pl023, | 2452 | .data = &vendor_st_pl023, |
2400 | }, | 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 | }, | ||
2401 | { 0, 0 }, | 2463 | { 0, 0 }, |
2402 | }; | 2464 | }; |
2403 | 2465 | ||