100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* 257cc097931e2d28a27e19515c549dc301ba6b6b2Grant Likely * MPC52xx PSC in SPI mode driver. 300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * 400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Maintainer: Dragos Carp 500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * 600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Copyright (C) 2006 TOPTICA Photonics AG. 700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * 800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * This program is free software; you can redistribute it and/or modify it 900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * under the terms of the GNU General Public License as published by the 1000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Free Software Foundation; either version 2 of the License, or (at your 1100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * option) any later version. 1200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp */ 1300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 1400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/module.h> 157390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov#include <linux/types.h> 1600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/errno.h> 1700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/interrupt.h> 1822ae782f86b726f9cea752c0f269ff6dcdf2f6e1Grant Likely#include <linux/of_address.h> 1976ef7dd030823518506d65237a12666fc3f5a0d4Stephen Rothwell#include <linux/of_platform.h> 2000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/workqueue.h> 2100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/completion.h> 2200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/io.h> 2300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/delay.h> 2400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/spi/spi.h> 2500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/fsl_devices.h> 265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 2800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <asm/mpc52xx.h> 2900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <asm/mpc52xx_psc.h> 3000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 3100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#define MCLK 20000000 /* PSC port MClk in hz */ 3200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 3300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstruct mpc52xx_psc_spi { 3400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* fsl_spi_platform data */ 357390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov void (*cs_control)(struct spi_device *spi, bool on); 3600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u32 sysclk; 3700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 3800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* driver internal data */ 3900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc __iomem *psc; 404874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely struct mpc52xx_psc_fifo __iomem *fifo; 4100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned int irq; 4200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u8 bits_per_word; 4300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u8 busy; 4400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 4500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct workqueue_struct *workqueue; 4600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct work_struct work; 4700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 4800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct list_head queue; 4900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spinlock_t lock; 5000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 5100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct completion done; 5200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}; 5300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 5400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* controller state */ 5500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstruct mpc52xx_psc_spi_cs { 5600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp int bits_per_word; 5700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp int speed_hz; 5800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}; 5900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 6000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* set clock freq, clock ramp, bits per work 6100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * if t is NULL then reset the values to the default values 6200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp */ 6300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi, 6400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_transfer *t) 6500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 6600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi_cs *cs = spi->controller_state; 6700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 6800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs->speed_hz = (t && t->speed_hz) 6900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ? t->speed_hz : spi->max_speed_hz; 7000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs->bits_per_word = (t && t->bits_per_word) 7100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ? t->bits_per_word : spi->bits_per_word; 7200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8; 7300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return 0; 7400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 7500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 7600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) 7700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 7800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi_cs *cs = spi->controller_state; 7900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 8000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc __iomem *psc = mps->psc; 8100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u32 sicr; 8200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u16 ccr; 8300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 8400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr = in_be32(&psc->sicr); 8500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 8600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* Set clock phase and polarity */ 8700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (spi->mode & SPI_CPHA) 8800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr |= 0x00001000; 8900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp else 9000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr &= ~0x00001000; 9100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (spi->mode & SPI_CPOL) 9200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr |= 0x00002000; 9300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp else 9400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr &= ~0x00002000; 9500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 9600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (spi->mode & SPI_LSB_FIRST) 9700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr |= 0x10000000; 9800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp else 9900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp sicr &= ~0x10000000; 10000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_be32(&psc->sicr, sicr); 10100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 10200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* Set clock frequency and bits per word 10300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Because psc->ccr is defined as 16bit register instead of 32bit 10400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * just set the lower byte of BitClkDiv 10500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp */ 106a897ea13f7a801e6baba8d4985f459042712244cGrant Likely ccr = in_be16((u16 __iomem *)&psc->ccr); 10700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ccr &= 0xFF00; 10800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (cs->speed_hz) 10900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ccr |= (MCLK / cs->speed_hz - 1) & 0xFF; 11000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp else /* by default SPI Clk 1MHz */ 11100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ccr |= (MCLK / 1000000 - 1) & 0xFF; 112a897ea13f7a801e6baba8d4985f459042712244cGrant Likely out_be16((u16 __iomem *)&psc->ccr, ccr); 11300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->bits_per_word = cs->bits_per_word; 11400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 1157390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov if (mps->cs_control) 1167390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); 11700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 11800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 11900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi) 12000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 12100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 12200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 1237390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov if (mps->cs_control) 1247390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); 12500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 12600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 12700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1) 12800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* wake up when 80% fifo full */ 12900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100) 13000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 13100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, 13200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_transfer *t) 13300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 13400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 13500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc __iomem *psc = mps->psc; 1364874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; 13700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned rb = 0; /* number of bytes receieved */ 13800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned sb = 0; /* number of bytes sent */ 13900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned char *rx_buf = (unsigned char *)t->rx_buf; 14000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned char *tx_buf = (unsigned char *)t->tx_buf; 14100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned rfalarm; 14200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned send_at_once = MPC52xx_PSC_BUFSIZE; 14300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned recv_at_once; 144b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic int last_block = 0; 14500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 14600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (!t->tx_buf && !t->rx_buf && t->len) 14700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return -EINVAL; 14800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 14900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* enable transmiter/receiver */ 15000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); 15100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp while (rb < t->len) { 15200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (t->len - rb > MPC52xx_PSC_BUFSIZE) { 15300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp rfalarm = MPC52xx_PSC_RFALARM; 154b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic last_block = 0; 15500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } else { 15600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp send_at_once = t->len - sb; 15700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb); 158b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic last_block = 1; 15900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 16000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 16100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); 1629a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu for (; send_at_once; sb++, send_at_once--) { 1639a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu /* set EOF flag before the last word is sent */ 164b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic if (send_at_once == 1 && last_block) 1659a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu out_8(&psc->ircr2, 0x01); 1669a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu 1679a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu if (tx_buf) 16800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); 1699a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu else 17000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->mpc52xx_psc_buffer_8, 0); 17100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 17200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 17300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 1743a4fa0a25da81600ea0bcd75692ae8ca6050d165Robert P. J. Day /* enable interrupts and wait for wake up 17500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * if just one byte is expected the Rx FIFO genererates no 17600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * FFULL interrupt, so activate the RxRDY interrupt 17700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp */ 17800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 17900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (t->len - rb == 1) { 18000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->mode, 0); 18100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } else { 18200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); 1834874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely out_be16(&fifo->rfalarm, rfalarm); 18400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 18500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY); 18600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp wait_for_completion(&mps->done); 1874874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely recv_at_once = in_be16(&fifo->rfnum); 18800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once); 18900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 19000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp send_at_once = recv_at_once; 19100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (rx_buf) { 19200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp for (; recv_at_once; rb++, recv_at_once--) 19300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8); 19400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } else { 19500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp for (; recv_at_once; rb++, recv_at_once--) 19600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp in_8(&psc->mpc52xx_psc_buffer_8); 19700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 19800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 19900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* disable transmiter/receiver */ 20000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); 20100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 20200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return 0; 20300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 20400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 20500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_work(struct work_struct *work) 20600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 20700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = 20800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp container_of(work, struct mpc52xx_psc_spi, work); 20900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 21000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_lock_irq(&mps->lock); 21100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->busy = 1; 21200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp while (!list_empty(&mps->queue)) { 21300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_message *m; 21400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_device *spi; 21500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_transfer *t = NULL; 21600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned cs_change; 21700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp int status; 21800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 21900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp m = container_of(mps->queue.next, struct spi_message, queue); 22000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp list_del_init(&m->queue); 22100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_unlock_irq(&mps->lock); 22200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 22300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spi = m->spi; 22400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs_change = 1; 22500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp status = 0; 22600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp list_for_each_entry (t, &m->transfers, transfer_list) { 22700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (t->bits_per_word || t->speed_hz) { 22800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp status = mpc52xx_psc_spi_transfer_setup(spi, t); 22900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (status < 0) 23000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp break; 23100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 23200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 23300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (cs_change) 23400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mpc52xx_psc_spi_activate_cs(spi); 23500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs_change = t->cs_change; 23600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 23700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp status = mpc52xx_psc_spi_transfer_rxtx(spi, t); 23800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (status) 23900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp break; 24000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp m->actual_length += t->len; 24100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 24200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (t->delay_usecs) 24300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp udelay(t->delay_usecs); 24400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 24500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (cs_change) 24600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mpc52xx_psc_spi_deactivate_cs(spi); 24700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 24800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 24900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp m->status = status; 2500a6d38795a405c49ea0012f04173613382def58cAxel Lin if (m->complete) 2510a6d38795a405c49ea0012f04173613382def58cAxel Lin m->complete(m->context); 25200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 25300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (status || !cs_change) 25400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mpc52xx_psc_spi_deactivate_cs(spi); 25500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 25600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mpc52xx_psc_spi_transfer_setup(spi, NULL); 25700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 25800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_lock_irq(&mps->lock); 25900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 26000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->busy = 0; 26100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_unlock_irq(&mps->lock); 26200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 26300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 26400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_setup(struct spi_device *spi) 26500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 26600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 26700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi_cs *cs = spi->controller_state; 26800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned long flags; 26900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 27000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (spi->bits_per_word%8) 27100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return -EINVAL; 27200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 27300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (!cs) { 27400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs = kzalloc(sizeof *cs, GFP_KERNEL); 27500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (!cs) 27600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return -ENOMEM; 27700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spi->controller_state = cs; 27800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 27900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 28000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs->bits_per_word = spi->bits_per_word; 28100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp cs->speed_hz = spi->max_speed_hz; 28200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 28300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_lock_irqsave(&mps->lock, flags); 28400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (!mps->busy) 28500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mpc52xx_psc_spi_deactivate_cs(spi); 28600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_unlock_irqrestore(&mps->lock, flags); 28700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 28800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return 0; 28900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 29000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 29100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_transfer(struct spi_device *spi, 29200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_message *m) 29300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 29400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 29500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp unsigned long flags; 29600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 29700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp m->actual_length = 0; 29800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp m->status = -EINPROGRESS; 29900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 30000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_lock_irqsave(&mps->lock, flags); 30100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp list_add_tail(&m->queue, &mps->queue); 30200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp queue_work(mps->workqueue, &mps->work); 30300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_unlock_irqrestore(&mps->lock, flags); 30400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 30500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return 0; 30600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 30700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 30800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_cleanup(struct spi_device *spi) 30900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 31000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp kfree(spi->controller_state); 31100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 31200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 31300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) 31400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 31500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc __iomem *psc = mps->psc; 3164874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; 31700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u32 mclken_div; 318f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang int ret; 31900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 32000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* default sysclk is 512MHz */ 3214fb4c5582475452d3bf7c5072ef2d15ee06f7723Grant Likely mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK; 322f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang ret = mpc52xx_set_psc_clkdiv(psc_id, mclken_div); 323f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang if (ret) 324f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang return ret; 32500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 32600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* Reset the PSC into a known state */ 32700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_RST_RX); 32800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_RST_TX); 32900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); 33000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 33100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* Disable interrupts, interrupts are based on alarm level */ 33200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_be16(&psc->mpc52xx_psc_imr, 0); 33300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 3344874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely out_8(&fifo->rfcntl, 0); 33500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); 33600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 33700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* Configure 8bit codec mode as a SPI master and use EOF flags */ 33800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */ 33900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_be32(&psc->sicr, 0x0180C800); 340a897ea13f7a801e6baba8d4985f459042712244cGrant Likely out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */ 34100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 34200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* Set 2ms DTL delay */ 34300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->ctur, 0x00); 34400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_8(&psc->ctlr, 0x84); 34500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 34600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->bits_per_word = 8; 34700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 348f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang return 0; 34900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 35000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 35100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id) 35200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 35300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id; 35400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc __iomem *psc = mps->psc; 35500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 35600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp /* disable interrupt and wake up the work queue */ 35700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) { 35800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp out_be16(&psc->mpc52xx_psc_imr, 0); 35900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp complete(&mps->done); 36000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return IRQ_HANDLED; 36100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 36200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return IRQ_NONE; 36300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 36400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 36500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* bus_num is used only for the case dev->platform_data == NULL */ 366fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, 36700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u32 size, unsigned int irq, s16 bus_num) 36800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 3698074cf063e410a2c0cf1704c3b31002e21f5df7cJingoo Han struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); 37000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct mpc52xx_psc_spi *mps; 37100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp struct spi_master *master; 37200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp int ret; 37300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 37400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master = spi_alloc_master(dev, sizeof *mps); 37500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (master == NULL) 37600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return -ENOMEM; 37700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 37800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp dev_set_drvdata(dev, master); 37900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps = spi_master_get_devdata(master); 38000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 381e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell /* the spi->mode bits understood by this driver: */ 382e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; 383e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell 38400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->irq = irq; 38500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (pdata == NULL) { 386f6bd03a746271f298aa5bfb6e049b245757efaedJarkko Nikula dev_warn(dev, 387f6bd03a746271f298aa5bfb6e049b245757efaedJarkko Nikula "probe called without platform data, no cs_control function will be called\n"); 3887390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov mps->cs_control = NULL; 38900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->sysclk = 0; 39000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->bus_num = bus_num; 39100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->num_chipselect = 255; 39200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } else { 3937390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov mps->cs_control = pdata->cs_control; 39400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->sysclk = pdata->sysclk; 39500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->bus_num = pdata->bus_num; 39600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->num_chipselect = pdata->max_chipselect; 39700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 39800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->setup = mpc52xx_psc_spi_setup; 39900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->transfer = mpc52xx_psc_spi_transfer; 40000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp master->cleanup = mpc52xx_psc_spi_cleanup; 40112b15e83289bc7cf2ec9a342412e0c955beeb395Anatolij Gustschin master->dev.of_node = dev->of_node; 40200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 40300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->psc = ioremap(regaddr, size); 40400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (!mps->psc) { 40500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp dev_err(dev, "could not ioremap I/O port range\n"); 40600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ret = -EFAULT; 40700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp goto free_master; 40800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 4094874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely /* On the 5200, fifo regs are immediately ajacent to the psc regs */ 4104874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc); 41100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 41200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi", 41300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps); 41400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (ret) 41500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp goto free_master; 41600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 41700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ret = mpc52xx_psc_spi_port_config(master->bus_num, mps); 418f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang if (ret < 0) { 419f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang dev_err(dev, "can't configure PSC! Is it capable of SPI?\n"); 42000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp goto free_irq; 421f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang } 42200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 42300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spin_lock_init(&mps->lock); 42400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp init_completion(&mps->done); 42500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp INIT_WORK(&mps->work, mpc52xx_psc_spi_work); 42600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp INIT_LIST_HEAD(&mps->queue); 42700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 42800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp mps->workqueue = create_singlethread_workqueue( 4296c7377ab6814c247d7600955a4ead2e3db490697Kay Sievers dev_name(master->dev.parent)); 43000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (mps->workqueue == NULL) { 43100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ret = -EBUSY; 43200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp goto free_irq; 43300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 43400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 43500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp ret = spi_register_master(master); 43600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (ret < 0) 43700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp goto unreg_master; 43800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 43900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return ret; 44000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 44100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpunreg_master: 44200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp destroy_workqueue(mps->workqueue); 44300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpfree_irq: 44400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp free_irq(mps->irq, mps); 44500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpfree_master: 44600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (mps->psc) 44700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp iounmap(mps->psc); 44800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp spi_master_put(master); 44900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 45000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return ret; 45100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 45200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 453fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int mpc52xx_psc_spi_of_probe(struct platform_device *op) 45400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 45500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp const u32 *regaddr_p; 45600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp u64 regaddr64, size64; 45700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp s16 id = -1; 45800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 45961c7a080a5a061c976988fd4b844dfb468dda255Grant Likely regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); 46000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (!regaddr_p) { 4615cc17d7e01abd77eda1267a75748cfc84c92a523Wolfram Sang dev_err(&op->dev, "Invalid PSC address\n"); 46200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp return -EINVAL; 46300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 46461c7a080a5a061c976988fd4b844dfb468dda255Grant Likely regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); 46500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 4668888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer /* get PSC id (1..6, used by port_config) */ 46700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp if (op->dev.platform_data == NULL) { 4688888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer const u32 *psc_nump; 46900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 47061c7a080a5a061c976988fd4b844dfb468dda255Grant Likely psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL); 4718888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer if (!psc_nump || *psc_nump > 5) { 4725cc17d7e01abd77eda1267a75748cfc84c92a523Wolfram Sang dev_err(&op->dev, "Invalid cell-index property\n"); 4738888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer return -EINVAL; 47400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 4758888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer id = *psc_nump + 1; 47600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp } 47700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 47812b15e83289bc7cf2ec9a342412e0c955beeb395Anatolij Gustschin return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64, 47961c7a080a5a061c976988fd4b844dfb468dda255Grant Likely irq_of_parse_and_map(op->dev.of_node, 0), id); 48000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 48100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 482fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int mpc52xx_psc_spi_of_remove(struct platform_device *op) 48300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{ 48424b5a82cf5709a4bc577f42fdaa61b23a7f58f08Jingoo Han struct spi_master *master = spi_master_get(platform_get_drvdata(op)); 4855aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); 4865aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang 4875aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang flush_workqueue(mps->workqueue); 4885aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang destroy_workqueue(mps->workqueue); 4895aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang spi_unregister_master(master); 4905aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang free_irq(mps->irq, mps); 4915aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang if (mps->psc) 4925aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang iounmap(mps->psc); 493c8c87c656f95d764eb2b460b46b0144794108da4Guenter Roeck spi_master_put(master); 4945aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang 4955aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang return 0; 49600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp} 49700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 498631e61b7ca12ef14c834f99f8948e410c539f585Márton Némethstatic const struct of_device_id mpc52xx_psc_spi_of_match[] = { 49966ffbe490b6156898364b3f20a571a78f8d77bc8Grant Likely { .compatible = "fsl,mpc5200-psc-spi", }, 50066ffbe490b6156898364b3f20a571a78f8d77bc8Grant Likely { .compatible = "mpc5200-psc-spi", }, /* old */ 50166ffbe490b6156898364b3f20a571a78f8d77bc8Grant Likely {} 50200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}; 50300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 50400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match); 50500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 50618d306d1375696b0e6b5b39e4744d7fa2ad5e170Grant Likelystatic struct platform_driver mpc52xx_psc_spi_of_driver = { 50700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp .probe = mpc52xx_psc_spi_of_probe, 508fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likely .remove = mpc52xx_psc_spi_of_remove, 50900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp .driver = { 51000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp .name = "mpc52xx-psc-spi", 51100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp .owner = THIS_MODULE, 5124018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .of_match_table = mpc52xx_psc_spi_of_match, 51300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp }, 51400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}; 515940ab88962bc1aff3273a8356d64577a6e386736Grant Likelymodule_platform_driver(mpc52xx_psc_spi_of_driver); 51600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp 51700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_AUTHOR("Dragos Carp"); 51800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_DESCRIPTION("MPC52xx PSC SPI Driver"); 51900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_LICENSE("GPL"); 520