162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale SPI/eSPI controller driver library. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Maintainer: Kumar Gala 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2006 Polycom, Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * CPM SPI and QE buffer descriptors mode support: 1062306a36Sopenharmony_ci * Copyright (c) 2009 MontaVista Software, Inc. 1162306a36Sopenharmony_ci * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Copyright 2010 Freescale Semiconductor, Inc. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1662306a36Sopenharmony_ci#include <linux/fsl_devices.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/spi/spi.h> 2462306a36Sopenharmony_ci#ifdef CONFIG_FSL_SOC 2562306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "spi-fsl-lib.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define MPC8XXX_SPI_RX_BUF(type) \ 3162306a36Sopenharmony_civoid mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ 3262306a36Sopenharmony_ci{ \ 3362306a36Sopenharmony_ci type *rx = mpc8xxx_spi->rx; \ 3462306a36Sopenharmony_ci *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ 3562306a36Sopenharmony_ci mpc8xxx_spi->rx = rx; \ 3662306a36Sopenharmony_ci} \ 3762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpc8xxx_spi_rx_buf_##type); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define MPC8XXX_SPI_TX_BUF(type) \ 4062306a36Sopenharmony_ciu32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ 4162306a36Sopenharmony_ci{ \ 4262306a36Sopenharmony_ci u32 data; \ 4362306a36Sopenharmony_ci const type *tx = mpc8xxx_spi->tx; \ 4462306a36Sopenharmony_ci if (!tx) \ 4562306a36Sopenharmony_ci return 0; \ 4662306a36Sopenharmony_ci data = *tx++ << mpc8xxx_spi->tx_shift; \ 4762306a36Sopenharmony_ci mpc8xxx_spi->tx = tx; \ 4862306a36Sopenharmony_ci return data; \ 4962306a36Sopenharmony_ci} \ 5062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpc8xxx_spi_tx_buf_##type); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciMPC8XXX_SPI_RX_BUF(u8) 5362306a36Sopenharmony_ciMPC8XXX_SPI_RX_BUF(u16) 5462306a36Sopenharmony_ciMPC8XXX_SPI_RX_BUF(u32) 5562306a36Sopenharmony_ciMPC8XXX_SPI_TX_BUF(u8) 5662306a36Sopenharmony_ciMPC8XXX_SPI_TX_BUF(u16) 5762306a36Sopenharmony_ciMPC8XXX_SPI_TX_BUF(u32) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(to_of_pinfo); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciconst char *mpc8xxx_spi_strmode(unsigned int flags) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci if (flags & SPI_QE_CPU_MODE) { 6862306a36Sopenharmony_ci return "QE CPU"; 6962306a36Sopenharmony_ci } else if (flags & SPI_CPM_MODE) { 7062306a36Sopenharmony_ci if (flags & SPI_QE) 7162306a36Sopenharmony_ci return "QE"; 7262306a36Sopenharmony_ci else if (flags & SPI_CPM2) 7362306a36Sopenharmony_ci return "CPM2"; 7462306a36Sopenharmony_ci else 7562306a36Sopenharmony_ci return "CPM1"; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci return "CPU"; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpc8xxx_spi_strmode); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid mpc8xxx_spi_probe(struct device *dev, struct resource *mem, 8262306a36Sopenharmony_ci unsigned int irq) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); 8562306a36Sopenharmony_ci struct spi_master *master; 8662306a36Sopenharmony_ci struct mpc8xxx_spi *mpc8xxx_spi; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci master = dev_get_drvdata(dev); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* the spi->mode bits understood by this driver: */ 9162306a36Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH 9262306a36Sopenharmony_ci | SPI_LSB_FIRST | SPI_LOOP; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci master->dev.of_node = dev->of_node; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci mpc8xxx_spi = spi_master_get_devdata(master); 9762306a36Sopenharmony_ci mpc8xxx_spi->dev = dev; 9862306a36Sopenharmony_ci mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8; 9962306a36Sopenharmony_ci mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8; 10062306a36Sopenharmony_ci mpc8xxx_spi->flags = pdata->flags; 10162306a36Sopenharmony_ci mpc8xxx_spi->spibrg = pdata->sysclk; 10262306a36Sopenharmony_ci mpc8xxx_spi->irq = irq; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci mpc8xxx_spi->rx_shift = 0; 10562306a36Sopenharmony_ci mpc8xxx_spi->tx_shift = 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci master->bus_num = pdata->bus_num; 10862306a36Sopenharmony_ci master->num_chipselect = pdata->max_chipselect; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci init_completion(&mpc8xxx_spi->done); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpc8xxx_spi_probe); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciint of_mpc8xxx_spi_probe(struct platform_device *ofdev) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct device *dev = &ofdev->dev; 11762306a36Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 11862306a36Sopenharmony_ci struct mpc8xxx_spi_probe_info *pinfo; 11962306a36Sopenharmony_ci struct fsl_spi_platform_data *pdata; 12062306a36Sopenharmony_ci const void *prop; 12162306a36Sopenharmony_ci int ret = -ENOMEM; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL); 12462306a36Sopenharmony_ci if (!pinfo) 12562306a36Sopenharmony_ci return ret; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci pdata = &pinfo->pdata; 12862306a36Sopenharmony_ci dev->platform_data = pdata; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Allocate bus num dynamically. */ 13162306a36Sopenharmony_ci pdata->bus_num = -1; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#ifdef CONFIG_FSL_SOC 13462306a36Sopenharmony_ci /* SPI controller is either clocked from QE or SoC clock. */ 13562306a36Sopenharmony_ci pdata->sysclk = get_brgfreq(); 13662306a36Sopenharmony_ci if (pdata->sysclk == -1) { 13762306a36Sopenharmony_ci pdata->sysclk = fsl_get_sys_freq(); 13862306a36Sopenharmony_ci if (pdata->sysclk == -1) 13962306a36Sopenharmony_ci return -ENODEV; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci#else 14262306a36Sopenharmony_ci ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk); 14362306a36Sopenharmony_ci if (ret) 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci#endif 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci prop = of_get_property(np, "mode", NULL); 14862306a36Sopenharmony_ci if (prop && !strcmp(prop, "cpu-qe")) 14962306a36Sopenharmony_ci pdata->flags = SPI_QE_CPU_MODE; 15062306a36Sopenharmony_ci else if (prop && !strcmp(prop, "qe")) 15162306a36Sopenharmony_ci pdata->flags = SPI_CPM_MODE | SPI_QE; 15262306a36Sopenharmony_ci else if (of_device_is_compatible(np, "fsl,cpm2-spi")) 15362306a36Sopenharmony_ci pdata->flags = SPI_CPM_MODE | SPI_CPM2; 15462306a36Sopenharmony_ci else if (of_device_is_compatible(np, "fsl,cpm1-spi")) 15562306a36Sopenharmony_ci pdata->flags = SPI_CPM_MODE | SPI_CPM1; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 162