162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2011, 2012 Cavium, Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/spi/spi.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/octeon/octeon.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "spi-cavium.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int octeon_spi_probe(struct platform_device *pdev) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci void __iomem *reg_base; 2262306a36Sopenharmony_ci struct spi_controller *host; 2362306a36Sopenharmony_ci struct octeon_spi *p; 2462306a36Sopenharmony_ci int err = -ENOENT; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci host = spi_alloc_host(&pdev->dev, sizeof(struct octeon_spi)); 2762306a36Sopenharmony_ci if (!host) 2862306a36Sopenharmony_ci return -ENOMEM; 2962306a36Sopenharmony_ci p = spi_controller_get_devdata(host); 3062306a36Sopenharmony_ci platform_set_drvdata(pdev, host); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci reg_base = devm_platform_ioremap_resource(pdev, 0); 3362306a36Sopenharmony_ci if (IS_ERR(reg_base)) { 3462306a36Sopenharmony_ci err = PTR_ERR(reg_base); 3562306a36Sopenharmony_ci goto fail; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci p->register_base = reg_base; 3962306a36Sopenharmony_ci p->sys_freq = octeon_get_io_clock_rate(); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci p->regs.config = 0; 4262306a36Sopenharmony_ci p->regs.status = 0x08; 4362306a36Sopenharmony_ci p->regs.tx = 0x10; 4462306a36Sopenharmony_ci p->regs.data = 0x80; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci host->num_chipselect = 4; 4762306a36Sopenharmony_ci host->mode_bits = SPI_CPHA | 4862306a36Sopenharmony_ci SPI_CPOL | 4962306a36Sopenharmony_ci SPI_CS_HIGH | 5062306a36Sopenharmony_ci SPI_LSB_FIRST | 5162306a36Sopenharmony_ci SPI_3WIRE; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci host->transfer_one_message = octeon_spi_transfer_one_message; 5462306a36Sopenharmony_ci host->bits_per_word_mask = SPI_BPW_MASK(8); 5562306a36Sopenharmony_ci host->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci host->dev.of_node = pdev->dev.of_node; 5862306a36Sopenharmony_ci err = devm_spi_register_controller(&pdev->dev, host); 5962306a36Sopenharmony_ci if (err) { 6062306a36Sopenharmony_ci dev_err(&pdev->dev, "register host failed: %d\n", err); 6162306a36Sopenharmony_ci goto fail; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci dev_info(&pdev->dev, "OCTEON SPI bus driver\n"); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_cifail: 6862306a36Sopenharmony_ci spi_controller_put(host); 6962306a36Sopenharmony_ci return err; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void octeon_spi_remove(struct platform_device *pdev) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct spi_controller *host = platform_get_drvdata(pdev); 7562306a36Sopenharmony_ci struct octeon_spi *p = spi_controller_get_devdata(host); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Clear the CSENA* and put everything in a known state. */ 7862306a36Sopenharmony_ci writeq(0, p->register_base + OCTEON_SPI_CFG(p)); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic const struct of_device_id octeon_spi_match[] = { 8262306a36Sopenharmony_ci { .compatible = "cavium,octeon-3010-spi", }, 8362306a36Sopenharmony_ci {}, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, octeon_spi_match); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic struct platform_driver octeon_spi_driver = { 8862306a36Sopenharmony_ci .driver = { 8962306a36Sopenharmony_ci .name = "spi-octeon", 9062306a36Sopenharmony_ci .of_match_table = octeon_spi_match, 9162306a36Sopenharmony_ci }, 9262306a36Sopenharmony_ci .probe = octeon_spi_probe, 9362306a36Sopenharmony_ci .remove_new = octeon_spi_remove, 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cimodule_platform_driver(octeon_spi_driver); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciMODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver"); 9962306a36Sopenharmony_ciMODULE_AUTHOR("David Daney"); 10062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 101