18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * MPC52xx PSC in SPI mode driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Maintainer: Dragos Carp 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2006 TOPTICA Photonics AG. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 168c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 178c2ecf20Sopenharmony_ci#include <linux/completion.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 218c2ecf20Sopenharmony_ci#include <linux/fsl_devices.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/mpc52xx.h> 258c2ecf20Sopenharmony_ci#include <asm/mpc52xx_psc.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define MCLK 20000000 /* PSC port MClk in hz */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mpc52xx_psc_spi { 308c2ecf20Sopenharmony_ci /* fsl_spi_platform data */ 318c2ecf20Sopenharmony_ci void (*cs_control)(struct spi_device *spi, bool on); 328c2ecf20Sopenharmony_ci u32 sysclk; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* driver internal data */ 358c2ecf20Sopenharmony_ci struct mpc52xx_psc __iomem *psc; 368c2ecf20Sopenharmony_ci struct mpc52xx_psc_fifo __iomem *fifo; 378c2ecf20Sopenharmony_ci unsigned int irq; 388c2ecf20Sopenharmony_ci u8 bits_per_word; 398c2ecf20Sopenharmony_ci u8 busy; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci struct work_struct work; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci struct list_head queue; 448c2ecf20Sopenharmony_ci spinlock_t lock; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci struct completion done; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* controller state */ 508c2ecf20Sopenharmony_cistruct mpc52xx_psc_spi_cs { 518c2ecf20Sopenharmony_ci int bits_per_word; 528c2ecf20Sopenharmony_ci int speed_hz; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* set clock freq, clock ramp, bits per work 568c2ecf20Sopenharmony_ci * if t is NULL then reset the values to the default values 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi, 598c2ecf20Sopenharmony_ci struct spi_transfer *t) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi_cs *cs = spi->controller_state; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci cs->speed_hz = (t && t->speed_hz) 648c2ecf20Sopenharmony_ci ? t->speed_hz : spi->max_speed_hz; 658c2ecf20Sopenharmony_ci cs->bits_per_word = (t && t->bits_per_word) 668c2ecf20Sopenharmony_ci ? t->bits_per_word : spi->bits_per_word; 678c2ecf20Sopenharmony_ci cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8; 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi_cs *cs = spi->controller_state; 748c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 758c2ecf20Sopenharmony_ci struct mpc52xx_psc __iomem *psc = mps->psc; 768c2ecf20Sopenharmony_ci u32 sicr; 778c2ecf20Sopenharmony_ci u16 ccr; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci sicr = in_be32(&psc->sicr); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Set clock phase and polarity */ 828c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPHA) 838c2ecf20Sopenharmony_ci sicr |= 0x00001000; 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci sicr &= ~0x00001000; 868c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 878c2ecf20Sopenharmony_ci sicr |= 0x00002000; 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci sicr &= ~0x00002000; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) 928c2ecf20Sopenharmony_ci sicr |= 0x10000000; 938c2ecf20Sopenharmony_ci else 948c2ecf20Sopenharmony_ci sicr &= ~0x10000000; 958c2ecf20Sopenharmony_ci out_be32(&psc->sicr, sicr); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Set clock frequency and bits per word 988c2ecf20Sopenharmony_ci * Because psc->ccr is defined as 16bit register instead of 32bit 998c2ecf20Sopenharmony_ci * just set the lower byte of BitClkDiv 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci ccr = in_be16((u16 __iomem *)&psc->ccr); 1028c2ecf20Sopenharmony_ci ccr &= 0xFF00; 1038c2ecf20Sopenharmony_ci if (cs->speed_hz) 1048c2ecf20Sopenharmony_ci ccr |= (MCLK / cs->speed_hz - 1) & 0xFF; 1058c2ecf20Sopenharmony_ci else /* by default SPI Clk 1MHz */ 1068c2ecf20Sopenharmony_ci ccr |= (MCLK / 1000000 - 1) & 0xFF; 1078c2ecf20Sopenharmony_ci out_be16((u16 __iomem *)&psc->ccr, ccr); 1088c2ecf20Sopenharmony_ci mps->bits_per_word = cs->bits_per_word; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (mps->cs_control) 1118c2ecf20Sopenharmony_ci mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (mps->cs_control) 1198c2ecf20Sopenharmony_ci mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1) 1238c2ecf20Sopenharmony_ci/* wake up when 80% fifo full */ 1248c2ecf20Sopenharmony_ci#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100) 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, 1278c2ecf20Sopenharmony_ci struct spi_transfer *t) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 1308c2ecf20Sopenharmony_ci struct mpc52xx_psc __iomem *psc = mps->psc; 1318c2ecf20Sopenharmony_ci struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; 1328c2ecf20Sopenharmony_ci unsigned rb = 0; /* number of bytes receieved */ 1338c2ecf20Sopenharmony_ci unsigned sb = 0; /* number of bytes sent */ 1348c2ecf20Sopenharmony_ci unsigned char *rx_buf = (unsigned char *)t->rx_buf; 1358c2ecf20Sopenharmony_ci unsigned char *tx_buf = (unsigned char *)t->tx_buf; 1368c2ecf20Sopenharmony_ci unsigned rfalarm; 1378c2ecf20Sopenharmony_ci unsigned send_at_once = MPC52xx_PSC_BUFSIZE; 1388c2ecf20Sopenharmony_ci unsigned recv_at_once; 1398c2ecf20Sopenharmony_ci int last_block = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!t->tx_buf && !t->rx_buf && t->len) 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* enable transmiter/receiver */ 1458c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); 1468c2ecf20Sopenharmony_ci while (rb < t->len) { 1478c2ecf20Sopenharmony_ci if (t->len - rb > MPC52xx_PSC_BUFSIZE) { 1488c2ecf20Sopenharmony_ci rfalarm = MPC52xx_PSC_RFALARM; 1498c2ecf20Sopenharmony_ci last_block = 0; 1508c2ecf20Sopenharmony_ci } else { 1518c2ecf20Sopenharmony_ci send_at_once = t->len - sb; 1528c2ecf20Sopenharmony_ci rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb); 1538c2ecf20Sopenharmony_ci last_block = 1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); 1578c2ecf20Sopenharmony_ci for (; send_at_once; sb++, send_at_once--) { 1588c2ecf20Sopenharmony_ci /* set EOF flag before the last word is sent */ 1598c2ecf20Sopenharmony_ci if (send_at_once == 1 && last_block) 1608c2ecf20Sopenharmony_ci out_8(&psc->ircr2, 0x01); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (tx_buf) 1638c2ecf20Sopenharmony_ci out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); 1648c2ecf20Sopenharmony_ci else 1658c2ecf20Sopenharmony_ci out_8(&psc->mpc52xx_psc_buffer_8, 0); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* enable interrupts and wait for wake up 1708c2ecf20Sopenharmony_ci * if just one byte is expected the Rx FIFO genererates no 1718c2ecf20Sopenharmony_ci * FFULL interrupt, so activate the RxRDY interrupt 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 1748c2ecf20Sopenharmony_ci if (t->len - rb == 1) { 1758c2ecf20Sopenharmony_ci out_8(&psc->mode, 0); 1768c2ecf20Sopenharmony_ci } else { 1778c2ecf20Sopenharmony_ci out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); 1788c2ecf20Sopenharmony_ci out_be16(&fifo->rfalarm, rfalarm); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY); 1818c2ecf20Sopenharmony_ci wait_for_completion(&mps->done); 1828c2ecf20Sopenharmony_ci recv_at_once = in_be16(&fifo->rfnum); 1838c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci send_at_once = recv_at_once; 1868c2ecf20Sopenharmony_ci if (rx_buf) { 1878c2ecf20Sopenharmony_ci for (; recv_at_once; rb++, recv_at_once--) 1888c2ecf20Sopenharmony_ci rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8); 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci for (; recv_at_once; rb++, recv_at_once--) 1918c2ecf20Sopenharmony_ci in_8(&psc->mpc52xx_psc_buffer_8); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci /* disable transmiter/receiver */ 1958c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void mpc52xx_psc_spi_work(struct work_struct *work) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = 2038c2ecf20Sopenharmony_ci container_of(work, struct mpc52xx_psc_spi, work); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci spin_lock_irq(&mps->lock); 2068c2ecf20Sopenharmony_ci mps->busy = 1; 2078c2ecf20Sopenharmony_ci while (!list_empty(&mps->queue)) { 2088c2ecf20Sopenharmony_ci struct spi_message *m; 2098c2ecf20Sopenharmony_ci struct spi_device *spi; 2108c2ecf20Sopenharmony_ci struct spi_transfer *t = NULL; 2118c2ecf20Sopenharmony_ci unsigned cs_change; 2128c2ecf20Sopenharmony_ci int status; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci m = container_of(mps->queue.next, struct spi_message, queue); 2158c2ecf20Sopenharmony_ci list_del_init(&m->queue); 2168c2ecf20Sopenharmony_ci spin_unlock_irq(&mps->lock); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci spi = m->spi; 2198c2ecf20Sopenharmony_ci cs_change = 1; 2208c2ecf20Sopenharmony_ci status = 0; 2218c2ecf20Sopenharmony_ci list_for_each_entry (t, &m->transfers, transfer_list) { 2228c2ecf20Sopenharmony_ci if (t->bits_per_word || t->speed_hz) { 2238c2ecf20Sopenharmony_ci status = mpc52xx_psc_spi_transfer_setup(spi, t); 2248c2ecf20Sopenharmony_ci if (status < 0) 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (cs_change) 2298c2ecf20Sopenharmony_ci mpc52xx_psc_spi_activate_cs(spi); 2308c2ecf20Sopenharmony_ci cs_change = t->cs_change; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci status = mpc52xx_psc_spi_transfer_rxtx(spi, t); 2338c2ecf20Sopenharmony_ci if (status) 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci m->actual_length += t->len; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci spi_transfer_delay_exec(t); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (cs_change) 2408c2ecf20Sopenharmony_ci mpc52xx_psc_spi_deactivate_cs(spi); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci m->status = status; 2448c2ecf20Sopenharmony_ci if (m->complete) 2458c2ecf20Sopenharmony_ci m->complete(m->context); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (status || !cs_change) 2488c2ecf20Sopenharmony_ci mpc52xx_psc_spi_deactivate_cs(spi); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci mpc52xx_psc_spi_transfer_setup(spi, NULL); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci spin_lock_irq(&mps->lock); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci mps->busy = 0; 2558c2ecf20Sopenharmony_ci spin_unlock_irq(&mps->lock); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_setup(struct spi_device *spi) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 2618c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi_cs *cs = spi->controller_state; 2628c2ecf20Sopenharmony_ci unsigned long flags; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (spi->bits_per_word%8) 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (!cs) { 2688c2ecf20Sopenharmony_ci cs = kzalloc(sizeof *cs, GFP_KERNEL); 2698c2ecf20Sopenharmony_ci if (!cs) 2708c2ecf20Sopenharmony_ci return -ENOMEM; 2718c2ecf20Sopenharmony_ci spi->controller_state = cs; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci cs->bits_per_word = spi->bits_per_word; 2758c2ecf20Sopenharmony_ci cs->speed_hz = spi->max_speed_hz; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci spin_lock_irqsave(&mps->lock, flags); 2788c2ecf20Sopenharmony_ci if (!mps->busy) 2798c2ecf20Sopenharmony_ci mpc52xx_psc_spi_deactivate_cs(spi); 2808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mps->lock, flags); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_transfer(struct spi_device *spi, 2868c2ecf20Sopenharmony_ci struct spi_message *m) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); 2898c2ecf20Sopenharmony_ci unsigned long flags; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci m->actual_length = 0; 2928c2ecf20Sopenharmony_ci m->status = -EINPROGRESS; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci spin_lock_irqsave(&mps->lock, flags); 2958c2ecf20Sopenharmony_ci list_add_tail(&m->queue, &mps->queue); 2968c2ecf20Sopenharmony_ci schedule_work(&mps->work); 2978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mps->lock, flags); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void mpc52xx_psc_spi_cleanup(struct spi_device *spi) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci kfree(spi->controller_state); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct mpc52xx_psc __iomem *psc = mps->psc; 3108c2ecf20Sopenharmony_ci struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; 3118c2ecf20Sopenharmony_ci u32 mclken_div; 3128c2ecf20Sopenharmony_ci int ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* default sysclk is 512MHz */ 3158c2ecf20Sopenharmony_ci mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK; 3168c2ecf20Sopenharmony_ci ret = mpc52xx_set_psc_clkdiv(psc_id, mclken_div); 3178c2ecf20Sopenharmony_ci if (ret) 3188c2ecf20Sopenharmony_ci return ret; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Reset the PSC into a known state */ 3218c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_RST_RX); 3228c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_RST_TX); 3238c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Disable interrupts, interrupts are based on alarm level */ 3268c2ecf20Sopenharmony_ci out_be16(&psc->mpc52xx_psc_imr, 0); 3278c2ecf20Sopenharmony_ci out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 3288c2ecf20Sopenharmony_ci out_8(&fifo->rfcntl, 0); 3298c2ecf20Sopenharmony_ci out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Configure 8bit codec mode as a SPI master and use EOF flags */ 3328c2ecf20Sopenharmony_ci /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */ 3338c2ecf20Sopenharmony_ci out_be32(&psc->sicr, 0x0180C800); 3348c2ecf20Sopenharmony_ci out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */ 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Set 2ms DTL delay */ 3378c2ecf20Sopenharmony_ci out_8(&psc->ctur, 0x00); 3388c2ecf20Sopenharmony_ci out_8(&psc->ctlr, 0x84); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci mps->bits_per_word = 8; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id; 3488c2ecf20Sopenharmony_ci struct mpc52xx_psc __iomem *psc = mps->psc; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* disable interrupt and wake up the work queue */ 3518c2ecf20Sopenharmony_ci if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) { 3528c2ecf20Sopenharmony_ci out_be16(&psc->mpc52xx_psc_imr, 0); 3538c2ecf20Sopenharmony_ci complete(&mps->done); 3548c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci return IRQ_NONE; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* bus_num is used only for the case dev->platform_data == NULL */ 3608c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, 3618c2ecf20Sopenharmony_ci u32 size, unsigned int irq, s16 bus_num) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); 3648c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps; 3658c2ecf20Sopenharmony_ci struct spi_master *master; 3668c2ecf20Sopenharmony_ci int ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci master = spi_alloc_master(dev, sizeof *mps); 3698c2ecf20Sopenharmony_ci if (master == NULL) 3708c2ecf20Sopenharmony_ci return -ENOMEM; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci dev_set_drvdata(dev, master); 3738c2ecf20Sopenharmony_ci mps = spi_master_get_devdata(master); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* the spi->mode bits understood by this driver: */ 3768c2ecf20Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci mps->irq = irq; 3798c2ecf20Sopenharmony_ci if (pdata == NULL) { 3808c2ecf20Sopenharmony_ci dev_warn(dev, 3818c2ecf20Sopenharmony_ci "probe called without platform data, no cs_control function will be called\n"); 3828c2ecf20Sopenharmony_ci mps->cs_control = NULL; 3838c2ecf20Sopenharmony_ci mps->sysclk = 0; 3848c2ecf20Sopenharmony_ci master->bus_num = bus_num; 3858c2ecf20Sopenharmony_ci master->num_chipselect = 255; 3868c2ecf20Sopenharmony_ci } else { 3878c2ecf20Sopenharmony_ci mps->cs_control = pdata->cs_control; 3888c2ecf20Sopenharmony_ci mps->sysclk = pdata->sysclk; 3898c2ecf20Sopenharmony_ci master->bus_num = pdata->bus_num; 3908c2ecf20Sopenharmony_ci master->num_chipselect = pdata->max_chipselect; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci master->setup = mpc52xx_psc_spi_setup; 3938c2ecf20Sopenharmony_ci master->transfer = mpc52xx_psc_spi_transfer; 3948c2ecf20Sopenharmony_ci master->cleanup = mpc52xx_psc_spi_cleanup; 3958c2ecf20Sopenharmony_ci master->dev.of_node = dev->of_node; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci mps->psc = ioremap(regaddr, size); 3988c2ecf20Sopenharmony_ci if (!mps->psc) { 3998c2ecf20Sopenharmony_ci dev_err(dev, "could not ioremap I/O port range\n"); 4008c2ecf20Sopenharmony_ci ret = -EFAULT; 4018c2ecf20Sopenharmony_ci goto free_master; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci /* On the 5200, fifo regs are immediately ajacent to the psc regs */ 4048c2ecf20Sopenharmony_ci mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi", 4078c2ecf20Sopenharmony_ci mps); 4088c2ecf20Sopenharmony_ci if (ret) 4098c2ecf20Sopenharmony_ci goto free_master; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ret = mpc52xx_psc_spi_port_config(master->bus_num, mps); 4128c2ecf20Sopenharmony_ci if (ret < 0) { 4138c2ecf20Sopenharmony_ci dev_err(dev, "can't configure PSC! Is it capable of SPI?\n"); 4148c2ecf20Sopenharmony_ci goto free_irq; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci spin_lock_init(&mps->lock); 4188c2ecf20Sopenharmony_ci init_completion(&mps->done); 4198c2ecf20Sopenharmony_ci INIT_WORK(&mps->work, mpc52xx_psc_spi_work); 4208c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mps->queue); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ret = spi_register_master(master); 4238c2ecf20Sopenharmony_ci if (ret < 0) 4248c2ecf20Sopenharmony_ci goto free_irq; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return ret; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cifree_irq: 4298c2ecf20Sopenharmony_ci free_irq(mps->irq, mps); 4308c2ecf20Sopenharmony_cifree_master: 4318c2ecf20Sopenharmony_ci if (mps->psc) 4328c2ecf20Sopenharmony_ci iounmap(mps->psc); 4338c2ecf20Sopenharmony_ci spi_master_put(master); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return ret; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_of_probe(struct platform_device *op) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci const u32 *regaddr_p; 4418c2ecf20Sopenharmony_ci u64 regaddr64, size64; 4428c2ecf20Sopenharmony_ci s16 id = -1; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); 4458c2ecf20Sopenharmony_ci if (!regaddr_p) { 4468c2ecf20Sopenharmony_ci dev_err(&op->dev, "Invalid PSC address\n"); 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* get PSC id (1..6, used by port_config) */ 4528c2ecf20Sopenharmony_ci if (op->dev.platform_data == NULL) { 4538c2ecf20Sopenharmony_ci const u32 *psc_nump; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL); 4568c2ecf20Sopenharmony_ci if (!psc_nump || *psc_nump > 5) { 4578c2ecf20Sopenharmony_ci dev_err(&op->dev, "Invalid cell-index property\n"); 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci id = *psc_nump + 1; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64, 4648c2ecf20Sopenharmony_ci irq_of_parse_and_map(op->dev.of_node, 0), id); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int mpc52xx_psc_spi_of_remove(struct platform_device *op) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct spi_master *master = spi_master_get(platform_get_drvdata(op)); 4708c2ecf20Sopenharmony_ci struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci flush_work(&mps->work); 4738c2ecf20Sopenharmony_ci spi_unregister_master(master); 4748c2ecf20Sopenharmony_ci free_irq(mps->irq, mps); 4758c2ecf20Sopenharmony_ci if (mps->psc) 4768c2ecf20Sopenharmony_ci iounmap(mps->psc); 4778c2ecf20Sopenharmony_ci spi_master_put(master); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic const struct of_device_id mpc52xx_psc_spi_of_match[] = { 4838c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc5200-psc-spi", }, 4848c2ecf20Sopenharmony_ci { .compatible = "mpc5200-psc-spi", }, /* old */ 4858c2ecf20Sopenharmony_ci {} 4868c2ecf20Sopenharmony_ci}; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic struct platform_driver mpc52xx_psc_spi_of_driver = { 4918c2ecf20Sopenharmony_ci .probe = mpc52xx_psc_spi_of_probe, 4928c2ecf20Sopenharmony_ci .remove = mpc52xx_psc_spi_of_remove, 4938c2ecf20Sopenharmony_ci .driver = { 4948c2ecf20Sopenharmony_ci .name = "mpc52xx-psc-spi", 4958c2ecf20Sopenharmony_ci .of_match_table = mpc52xx_psc_spi_of_match, 4968c2ecf20Sopenharmony_ci }, 4978c2ecf20Sopenharmony_ci}; 4988c2ecf20Sopenharmony_cimodule_platform_driver(mpc52xx_psc_spi_of_driver); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dragos Carp"); 5018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MPC52xx PSC SPI Driver"); 5028c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 503