ontent='index, nofollow'/>
aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/spi/spi-fsl-espi.c
blob: 80d245ac846fa366abf8d2b7511a1fb4ac25c03e (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                           
                        
                      
                              


                            

                     

                             
                              

                                  

                           
                        

























































































































                                                                               








                                                 
                


                                                         















                                                                          
                                                                    
 
                                                                            
                                                                           


                                                                               
                
                                                               


                     

                       





























                                                                              

                





                                    
                                              





















                                                                              
                                                                
 
                  





                                          
                                                     
 
                























                                                                       

                                                                                                     



























































                                                                             
                                       









                                                                             
                                                 




                               



                                






                                                           

                                                                            

                      
                            



                                                                         

                                                          


                         







                                                                             

                                                            
                                       

                                                           
 
                                            
                                               
                                               

                                                 





                                                                             

                             
                                                                               






                                                                     

                                                         




                               
                                  








                                                              

                                               



                               
                                  









                                                          

                                             








                                                 
                                                         




                               
                                                      

                                       
                                         




                                                          
                                                           



























                                                                         







                                                         





                                                           

                                 





                                                                        
 













                                                                           





















































                                                                             































                                                       
                                                             

                                                       
                                                                    


                                        



                               








                                                                   
                                         
 
                                                               
                                       
                                           
                                                           

                                                               

                                                     



























                                                                        

























                                                                      


























                                                                          
                                                                    














                                                                         
                                                           




                                                    
                         

                          
                                          










                                                  
                                          
                   



                              
                                                










                                      
                                                          



                                             



                                                         

                





                                                         
                                        




































                                                                             





                                                        
                                                 

                                   
                                                    
                               

                                            
                                             
  
                                        



                                                    
/*
 * Freescale eSPI controller driver.
 *
 * Copyright 2010 Freescale Semiconductor, Inc.
 *
 * 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
 * option) any later version.
 */
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fsl_devices.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <sysdev/fsl_soc.h>

#include "spi-fsl-lib.h"

/* eSPI Controller registers */
struct fsl_espi_reg {
	__be32 mode;		/* 0x000 - eSPI mode register */
	__be32 event;		/* 0x004 - eSPI event register */
	__be32 mask;		/* 0x008 - eSPI mask register */
	__be32 command;		/* 0x00c - eSPI command register */
	__be32 transmit;	/* 0x010 - eSPI transmit FIFO access register*/
	__be32 receive;		/* 0x014 - eSPI receive FIFO access register*/
	u8 res[8];		/* 0x018 - 0x01c reserved */
	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode register */
};

struct fsl_espi_transfer {
	const void *tx_buf;
	void *rx_buf;
	unsigned len;
	unsigned n_tx;
	unsigned n_rx;
	unsigned actual_length;
	int status;
};

/* eSPI Controller mode register definitions */
#define SPMODE_ENABLE		(1 << 31)
#define SPMODE_LOOP		(1 << 30)
#define SPMODE_TXTHR(x)		((x) << 8)
#define SPMODE_RXTHR(x)		((x) << 0)

/* eSPI Controller CS mode register definitions */
#define CSMODE_CI_INACTIVEHIGH	(1 << 31)
#define CSMODE_CP_BEGIN_EDGECLK	(1 << 30)
#define CSMODE_REV		(1 << 29)
#define CSMODE_DIV16		(1 << 28)
#define CSMODE_PM(x)		((x) << 24)
#define CSMODE_POL_1		(1 << 20)
#define CSMODE_LEN(x)		((x) << 16)
#define CSMODE_BEF(x)		((x) << 12)
#define CSMODE_AFT(x)		((x) << 8)
#define CSMODE_CG(x)		((x) << 3)

/* Default mode/csmode for eSPI controller */
#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
		| CSMODE_AFT(0) | CSMODE_CG(1))

/* SPIE register values */
#define	SPIE_NE		0x00000200	/* Not empty */
#define	SPIE_NF		0x00000100	/* Not full */

/* SPIM register values */
#define	SPIM_NE		0x00000200	/* Not empty */
#define	SPIM_NF		0x00000100	/* Not full */
#define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
#define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)

/* SPCOM register values */
#define SPCOM_CS(x)		((x) << 30)
#define SPCOM_TRANLEN(x)	((x) << 0)
#define	SPCOM_TRANLEN_MAX	0xFFFF	/* Max transaction length */

static void fsl_espi_change_mode(struct spi_device *spi)
{
	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
	struct spi_mpc8xxx_cs *cs = spi->controller_state;
	struct fsl_espi_reg *reg_base = mspi->reg_base;
	__be32 __iomem *mode = &reg_base->csmode[spi->chip_select];
	__be32 __iomem *espi_mode = &reg_base->mode;
	u32 tmp;
	unsigned long flags;

	/* Turn off IRQs locally to minimize time that SPI is disabled. */
	local_irq_save(flags);

	/* Turn off SPI unit prior changing mode */
	tmp = mpc8xxx_spi_read_reg(espi_mode);
	mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
	mpc8xxx_spi_write_reg(espi_mode, tmp);

	local_irq_restore(flags);
}

static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
{
	u32 data;
	u16 data_h;
	u16 data_l;
	const u32 *tx = mpc8xxx_spi->tx;

	if (!tx)
		return 0;

	data = *tx++ << mpc8xxx_spi->tx_shift;
	data_l = data & 0xffff;
	data_h = (data >> 16) & 0xffff;
	swab16s(&data_l);
	swab16s(&data_h);
	data = data_h | data_l;

	mpc8xxx_spi->tx = tx;
	return data;
}

static int fsl_espi_setup_transfer(struct spi_device *spi,
					struct spi_transfer *t)
{
	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
	int bits_per_word = 0;
	u8 pm;
	u32 hz = 0;
	struct spi_mpc8xxx_cs *cs = spi->controller_state;

	if (t) {
		bits_per_word = t->bits_per_word;
		hz = t->speed_hz;
	}

	/* spi_transfer level calls that work per-word */
	if (!bits_per_word)
		bits_per_word = spi->bits_per_word;

	if (!hz)
		hz = spi->max_speed_hz;

	cs->rx_shift = 0;
	cs->tx_shift = 0;
	cs->get_rx = mpc8xxx_spi_rx_buf_u32;
	cs->get_tx = mpc8xxx_spi_tx_buf_u32;
	if (bits_per_word <= 8) {
		cs->rx_shift = 8 - bits_per_word;