Commit 447b0c7b939f1d9e4024edf07a471ce7b1bcf002

Authored by Andreas Larsson
Committed by Grant Likely
1 parent 8922a366dd

spi/spi-fsl-spi: Add support for Aeroflex Gaisler GRLIB cores normally running on SPARC

This adds support for the mostly register-compatible SPICTRL cores from the
GRLIB VHDL IP core library from Aeroflex Gaisler. They are normally running on
SPARC. A different entry in of_fsl_spi_match matches this core and indicates a
different hardware type that is used to set up different function pointers and
special cases.

The GRLIB core operates in cpu mode. The number of bits per word might be
limited. There might be native chipselects selected via a slave select
register. These differences to the FSL type cores, if present, are indicated by
a capabilities register. Other register and function differences exists but are
not relevant to the driver.

Acked-by: Anton Vorontsov <anton@enomsg.org>
Signed-off-by: Andreas Larsson <andreas@gaisler.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

Showing 5 changed files with 103 additions and 15 deletions Side-by-side Diff

Documentation/devicetree/bindings/spi/fsl-spi.txt
... ... @@ -4,7 +4,7 @@
4 4 - cell-index : QE SPI subblock index.
5 5 0: QE subblock SPI1
6 6 1: QE subblock SPI2
7   -- compatible : should be "fsl,spi".
  7 +- compatible : should be "fsl,spi" or "aeroflexgaisler,spictrl".
8 8 - mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
9 9 - reg : Offset and length of the register set for the device
10 10 - interrupts : <a b> where a is the interrupt number and b is a
Documentation/devicetree/bindings/vendor-prefixes.txt
... ... @@ -5,6 +5,7 @@
5 5  
6 6 ad Avionic Design GmbH
7 7 adi Analog Devices, Inc.
  8 +aeroflexgaisler Aeroflex Gaisler AB
8 9 ak Asahi Kasei Corp.
9 10 amcc Applied Micro Circuits Corporation (APM, formally AMCC)
10 11 apm Applied Micro Circuits Corporation (APM)
... ... @@ -236,7 +236,7 @@
236 236 depends on FSL_SOC
237 237  
238 238 config SPI_FSL_SPI
239   - bool "Freescale SPI controller"
  239 + bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
240 240 depends on OF
241 241 select SPI_FSL_LIB
242 242 select SPI_FSL_CPM if FSL_SOC
... ... @@ -244,6 +244,8 @@
244 244 This enables using the Freescale SPI controllers in master mode.
245 245 MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
246 246 MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
  247 + This also enables using the Aeroflex Gaisler GRLIB SPI controller in
  248 + master mode.
247 249  
248 250 config SPI_FSL_ESPI
249 251 bool "Freescale eSPI controller"
drivers/spi/spi-fsl-spi.c
... ... @@ -10,6 +10,10 @@
10 10 * Copyright (c) 2009 MontaVista Software, Inc.
11 11 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
12 12 *
  13 + * GRLIB support:
  14 + * Copyright (c) 2012 Aeroflex Gaisler AB.
  15 + * Author: Andreas Larsson <andreas@gaisler.com>
  16 + *
13 17 * This program is free software; you can redistribute it and/or modify it
14 18 * under the terms of the GNU General Public License as published by the
15 19 * Free Software Foundation; either version 2 of the License, or (at your
... ... @@ -40,6 +44,7 @@
40 44 #include "spi-fsl-spi.h"
41 45  
42 46 #define TYPE_FSL 0
  47 +#define TYPE_GRLIB 1
43 48  
44 49 struct fsl_spi_match_data {
45 50 int type;
46 51  
... ... @@ -49,11 +54,19 @@
49 54 .type = TYPE_FSL,
50 55 };
51 56  
  57 +static struct fsl_spi_match_data of_fsl_spi_grlib_config = {
  58 + .type = TYPE_GRLIB,
  59 +};
  60 +
52 61 static struct of_device_id of_fsl_spi_match[] = {
53 62 {
54 63 .compatible = "fsl,spi",
55 64 .data = &of_fsl_spi_fsl_config,
56 65 },
  66 + {
  67 + .compatible = "aeroflexgaisler,spictrl",
  68 + .data = &of_fsl_spi_grlib_config,
  69 + },
57 70 {}
58 71 };
59 72 MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
... ... @@ -141,6 +154,21 @@
141 154 }
142 155 }
143 156  
  157 +static void fsl_spi_grlib_set_shifts(u32 *rx_shift, u32 *tx_shift,
  158 + int bits_per_word, int msb_first)
  159 +{
  160 + *rx_shift = 0;
  161 + *tx_shift = 0;
  162 + if (bits_per_word <= 16) {
  163 + if (msb_first) {
  164 + *rx_shift = 16; /* LSB in bit 16 */
  165 + *tx_shift = 32 - bits_per_word; /* MSB in bit 31 */
  166 + } else {
  167 + *rx_shift = 16 - bits_per_word; /* MSB in bit 15 */
  168 + }
  169 + }
  170 +}
  171 +
144 172 static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
145 173 struct spi_device *spi,
146 174 struct mpc8xxx_spi *mpc8xxx_spi,
... ... @@ -494,6 +522,42 @@
494 522 fsl_spi_cpm_free(mspi);
495 523 }
496 524  
  525 +static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
  526 +{
  527 + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
  528 + struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
  529 + u32 slvsel;
  530 + u16 cs = spi->chip_select;
  531 +
  532 + slvsel = mpc8xxx_spi_read_reg(&reg_base->slvsel);
  533 + slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs));
  534 + mpc8xxx_spi_write_reg(&reg_base->slvsel, slvsel);
  535 +}
  536 +
  537 +static void fsl_spi_grlib_probe(struct device *dev)
  538 +{
  539 + struct fsl_spi_platform_data *pdata = dev->platform_data;
  540 + struct spi_master *master = dev_get_drvdata(dev);
  541 + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
  542 + struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
  543 + int mbits;
  544 + u32 capabilities;
  545 +
  546 + capabilities = mpc8xxx_spi_read_reg(&reg_base->cap);
  547 +
  548 + mpc8xxx_spi->set_shifts = fsl_spi_grlib_set_shifts;
  549 + mbits = SPCAP_MAXWLEN(capabilities);
  550 + if (mbits)
  551 + mpc8xxx_spi->max_bits_per_word = mbits + 1;
  552 +
  553 + master->num_chipselect = 1; /* Allow for an always selected chip */
  554 + if (SPCAP_SSEN(capabilities)) {
  555 + master->num_chipselect = SPCAP_SSSZ(capabilities);
  556 + mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
  557 + }
  558 + pdata->cs_control = fsl_spi_grlib_cs_control;
  559 +}
  560 +
497 561 static struct spi_master * fsl_spi_probe(struct device *dev,
498 562 struct resource *mem, unsigned int irq)
499 563 {
... ... @@ -528,6 +592,15 @@
528 592 if (ret)
529 593 goto err_cpm_init;
530 594  
  595 + mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
  596 + if (mpc8xxx_spi->reg_base == NULL) {
  597 + ret = -ENOMEM;
  598 + goto err_ioremap;
  599 + }
  600 +
  601 + if (mpc8xxx_spi->type == TYPE_GRLIB)
  602 + fsl_spi_grlib_probe(dev);
  603 +
531 604 if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
532 605 mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
533 606  
... ... @@ -536,12 +609,6 @@
536 609 mpc8xxx_spi->set_shifts(&mpc8xxx_spi->rx_shift,
537 610 &mpc8xxx_spi->tx_shift, 8, 1);
538 611  
539   - mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
540   - if (mpc8xxx_spi->reg_base == NULL) {
541   - ret = -ENOMEM;
542   - goto err_ioremap;
543   - }
544   -
545 612 /* Register for SPI Interrupt */
546 613 ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
547 614 0, "fsl_spi", mpc8xxx_spi);
548 615  
... ... @@ -706,16 +773,19 @@
706 773 struct device_node *np = ofdev->dev.of_node;
707 774 struct spi_master *master;
708 775 struct resource mem;
709   - int irq;
  776 + int irq, type;
710 777 int ret = -ENOMEM;
711 778  
712 779 ret = of_mpc8xxx_spi_probe(ofdev);
713 780 if (ret)
714 781 return ret;
715 782  
716   - ret = of_fsl_spi_get_chipselects(dev);
717   - if (ret)
718   - goto err;
  783 + type = fsl_spi_get_type(&ofdev->dev);
  784 + if (type == TYPE_FSL) {
  785 + ret = of_fsl_spi_get_chipselects(dev);
  786 + if (ret)
  787 + goto err;
  788 + }
719 789  
720 790 ret = of_address_to_resource(np, 0, &mem);
721 791 if (ret)
722 792  
723 793  
... ... @@ -736,18 +806,22 @@
736 806 return 0;
737 807  
738 808 err:
739   - of_fsl_spi_free_chipselects(dev);
  809 + if (type == TYPE_FSL)
  810 + of_fsl_spi_free_chipselects(dev);
740 811 return ret;
741 812 }
742 813  
743 814 static int of_fsl_spi_remove(struct platform_device *ofdev)
744 815 {
  816 + struct spi_master *master = dev_get_drvdata(&ofdev->dev);
  817 + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
745 818 int ret;
746 819  
747 820 ret = mpc8xxx_spi_remove(&ofdev->dev);
748 821 if (ret)
749 822 return ret;
750   - of_fsl_spi_free_chipselects(&ofdev->dev);
  823 + if (mpc8xxx_spi->type == TYPE_FSL)
  824 + of_fsl_spi_free_chipselects(&ofdev->dev);
751 825 return 0;
752 826 }
753 827  
drivers/spi/spi-fsl-spi.h
... ... @@ -10,6 +10,10 @@
10 10 * Copyright (c) 2009 MontaVista Software, Inc.
11 11 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
12 12 *
  13 + * GRLIB support:
  14 + * Copyright (c) 2012 Aeroflex Gaisler AB.
  15 + * Author: Andreas Larsson <andreas@gaisler.com>
  16 + *
13 17 * This program is free software; you can redistribute it and/or modify it
14 18 * under the terms of the GNU General Public License as published by the
15 19 * Free Software Foundation; either version 2 of the License, or (at your
16 20  
... ... @@ -21,13 +25,15 @@
21 25  
22 26 /* SPI Controller registers */
23 27 struct fsl_spi_reg {
24   - u8 res1[0x20];
  28 + __be32 cap; /* TYPE_GRLIB specific */
  29 + u8 res1[0x1C];
25 30 __be32 mode;
26 31 __be32 event;
27 32 __be32 mask;
28 33 __be32 command;
29 34 __be32 transmit;
30 35 __be32 receive;
  36 + __be32 slvsel; /* TYPE_GRLIB specific */
31 37 };
32 38  
33 39 /* SPI Controller mode register definitions */
... ... @@ -42,6 +48,11 @@
42 48 #define SPMODE_PM(x) ((x) << 16)
43 49 #define SPMODE_OP (1 << 14)
44 50 #define SPMODE_CG(x) ((x) << 7)
  51 +
  52 +/* TYPE_GRLIB SPI Controller capability register definitions */
  53 +#define SPCAP_SSEN(x) (((x) >> 16) & 0x1)
  54 +#define SPCAP_SSSZ(x) (((x) >> 24) & 0xff)
  55 +#define SPCAP_MAXWLEN(x) (((x) >> 20) & 0xf)
45 56  
46 57 /*
47 58 * Default for SPI Mode: