diff options
Diffstat (limited to 'drivers/spi')
| -rw-r--r-- | drivers/spi/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/spi/spi-fsl-spi.c | 98 | ||||
| -rw-r--r-- | drivers/spi/spi-fsl-spi.h | 13 | 
3 files changed, 101 insertions, 14 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3524bec5ae5..2946ab4736f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -236,7 +236,7 @@ config SPI_FSL_CPM  	depends on FSL_SOC  config SPI_FSL_SPI -	bool "Freescale SPI controller" +	bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"  	depends on OF  	select SPI_FSL_LIB  	select SPI_FSL_CPM if FSL_SOC @@ -244,6 +244,8 @@ config SPI_FSL_SPI  	  This enables using the Freescale SPI controllers in master mode.  	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.  	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode. +	  This also enables using the Aeroflex Gaisler GRLIB SPI controller in +	  master mode.  config SPI_FSL_ESPI  	bool "Freescale eSPI controller" diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 7eff63a284f..6846459e5c9 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -10,6 +10,10 @@   * Copyright (c) 2009  MontaVista Software, Inc.   * Author: Anton Vorontsov <avorontsov@ru.mvista.com>   * + * GRLIB support: + * Copyright (c) 2012 Aeroflex Gaisler AB. + * Author: Andreas Larsson <andreas@gaisler.com> + *   * This program is free software; you can redistribute  it and/or modify it   * under  the terms of  the GNU General  Public License as published by the   * Free Software Foundation;  either version 2 of the  License, or (at your @@ -40,6 +44,7 @@  #include "spi-fsl-spi.h"  #define TYPE_FSL	0 +#define TYPE_GRLIB	1  struct fsl_spi_match_data {  	int type; @@ -49,11 +54,19 @@ static struct fsl_spi_match_data of_fsl_spi_fsl_config = {  	.type = TYPE_FSL,  }; +static struct fsl_spi_match_data of_fsl_spi_grlib_config = { +	.type = TYPE_GRLIB, +}; +  static struct of_device_id of_fsl_spi_match[] = {  	{  		.compatible = "fsl,spi",  		.data = &of_fsl_spi_fsl_config,  	}, +	{ +		.compatible = "aeroflexgaisler,spictrl", +		.data = &of_fsl_spi_grlib_config, +	},  	{}  };  MODULE_DEVICE_TABLE(of, of_fsl_spi_match); @@ -141,6 +154,21 @@ static void fsl_spi_qe_cpu_set_shifts(u32 *rx_shift, u32 *tx_shift,  	}  } +static void fsl_spi_grlib_set_shifts(u32 *rx_shift, u32 *tx_shift, +				     int bits_per_word, int msb_first) +{ +	*rx_shift = 0; +	*tx_shift = 0; +	if (bits_per_word <= 16) { +		if (msb_first) { +			*rx_shift = 16; /* LSB in bit 16 */ +			*tx_shift = 32 - bits_per_word; /* MSB in bit 31 */ +		} else { +			*rx_shift = 16 - bits_per_word; /* MSB in bit 15 */ +		} +	} +} +  static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,  				struct spi_device *spi,  				struct mpc8xxx_spi *mpc8xxx_spi, @@ -494,6 +522,42 @@ static void fsl_spi_remove(struct mpc8xxx_spi *mspi)  	fsl_spi_cpm_free(mspi);  } +static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) +{ +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); +	struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; +	u32 slvsel; +	u16 cs = spi->chip_select; + +	slvsel = mpc8xxx_spi_read_reg(®_base->slvsel); +	slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs)); +	mpc8xxx_spi_write_reg(®_base->slvsel, slvsel); +} + +static void fsl_spi_grlib_probe(struct device *dev) +{ +	struct fsl_spi_platform_data *pdata = dev->platform_data; +	struct spi_master *master = dev_get_drvdata(dev); +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); +	struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; +	int mbits; +	u32 capabilities; + +	capabilities = mpc8xxx_spi_read_reg(®_base->cap); + +	mpc8xxx_spi->set_shifts = fsl_spi_grlib_set_shifts; +	mbits = SPCAP_MAXWLEN(capabilities); +	if (mbits) +		mpc8xxx_spi->max_bits_per_word = mbits + 1; + +	master->num_chipselect = 1; /* Allow for an always selected chip */ +	if (SPCAP_SSEN(capabilities)) { +		master->num_chipselect = SPCAP_SSSZ(capabilities); +		mpc8xxx_spi_write_reg(®_base->slvsel, 0xffffffff); +	} +	pdata->cs_control = fsl_spi_grlib_cs_control; +} +  static struct spi_master * fsl_spi_probe(struct device *dev,  		struct resource *mem, unsigned int irq)  { @@ -528,6 +592,15 @@ static struct spi_master * fsl_spi_probe(struct device *dev,  	if (ret)  		goto err_cpm_init; +	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); +	if (mpc8xxx_spi->reg_base == NULL) { +		ret = -ENOMEM; +		goto err_ioremap; +	} + +	if (mpc8xxx_spi->type == TYPE_GRLIB) +		fsl_spi_grlib_probe(dev); +  	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)  		mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts; @@ -536,12 +609,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev,  		mpc8xxx_spi->set_shifts(&mpc8xxx_spi->rx_shift,  					&mpc8xxx_spi->tx_shift, 8, 1); -	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); -	if (mpc8xxx_spi->reg_base == NULL) { -		ret = -ENOMEM; -		goto err_ioremap; -	} -  	/* Register for SPI Interrupt */  	ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,  			  0, "fsl_spi", mpc8xxx_spi); @@ -706,16 +773,19 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)  	struct device_node *np = ofdev->dev.of_node;  	struct spi_master *master;  	struct resource mem; -	int irq; +	int irq, type;  	int ret = -ENOMEM;  	ret = of_mpc8xxx_spi_probe(ofdev);  	if (ret)  		return ret; -	ret = of_fsl_spi_get_chipselects(dev); -	if (ret) -		goto err; +	type = fsl_spi_get_type(&ofdev->dev); +	if (type == TYPE_FSL) { +		ret = of_fsl_spi_get_chipselects(dev); +		if (ret) +			goto err; +	}  	ret = of_address_to_resource(np, 0, &mem);  	if (ret) @@ -736,18 +806,22 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)  	return 0;  err: -	of_fsl_spi_free_chipselects(dev); +	if (type == TYPE_FSL) +		of_fsl_spi_free_chipselects(dev);  	return ret;  }  static int of_fsl_spi_remove(struct platform_device *ofdev)  { +	struct spi_master *master = dev_get_drvdata(&ofdev->dev); +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);  	int ret;  	ret = mpc8xxx_spi_remove(&ofdev->dev);  	if (ret)  		return ret; -	of_fsl_spi_free_chipselects(&ofdev->dev); +	if (mpc8xxx_spi->type == TYPE_FSL) +		of_fsl_spi_free_chipselects(&ofdev->dev);  	return 0;  } diff --git a/drivers/spi/spi-fsl-spi.h b/drivers/spi/spi-fsl-spi.h index 8bd73a4318e..9a6dae00e3f 100644 --- a/drivers/spi/spi-fsl-spi.h +++ b/drivers/spi/spi-fsl-spi.h @@ -10,6 +10,10 @@   * Copyright (c) 2009  MontaVista Software, Inc.   * Author: Anton Vorontsov <avorontsov@ru.mvista.com>   * + * GRLIB support: + * Copyright (c) 2012 Aeroflex Gaisler AB. + * Author: Andreas Larsson <andreas@gaisler.com> + *   * This program is free software; you can redistribute  it and/or modify it   * under  the terms of  the GNU General  Public License as published by the   * Free Software Foundation;  either version 2 of the  License, or (at your @@ -21,13 +25,15 @@  /* SPI Controller registers */  struct fsl_spi_reg { -	u8 res1[0x20]; +	__be32 cap; /* TYPE_GRLIB specific */ +	u8 res1[0x1C];  	__be32 mode;  	__be32 event;  	__be32 mask;  	__be32 command;  	__be32 transmit;  	__be32 receive; +	__be32 slvsel; /* TYPE_GRLIB specific */  };  /* SPI Controller mode register definitions */ @@ -43,6 +49,11 @@ struct fsl_spi_reg {  #define	SPMODE_OP		(1 << 14)  #define	SPMODE_CG(x)		((x) << 7) +/* TYPE_GRLIB SPI Controller capability register definitions */ +#define SPCAP_SSEN(x)		(((x) >> 16) & 0x1) +#define SPCAP_SSSZ(x)		(((x) >> 24) & 0xff) +#define SPCAP_MAXWLEN(x)	(((x) >> 20) & 0xf) +  /*   * Default for SPI Mode:   *	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk  |