1 /* 2 * CLPS711X SPI bus driver 3 * 4 * Copyright (C) 2012-2016 Alexander Shiyan <shc_work@mail.ru> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12 #include <linux/io.h> 13 #include <linux/clk.h> 14 #include <linux/gpio.h> 15 #include <linux/module.h> 16 #include <linux/interrupt.h> 17 #include <linux/platform_device.h> 18 #include <linux/regmap.h> 19 #include <linux/mfd/syscon.h> 20 #include <linux/mfd/syscon/clps711x.h> 21 #include <linux/spi/spi.h> 22 23 #define DRIVER_NAME "clps711x-spi" 24 25 #define SYNCIO_FRMLEN(x) ((x) << 8) 26 #define SYNCIO_TXFRMEN (1 << 14) 27 28 struct spi_clps711x_data { 29 void __iomem *syncio; 30 struct regmap *syscon; 31 struct clk *spi_clk; 32 33 u8 *tx_buf; 34 u8 *rx_buf; 35 unsigned int bpw; 36 int len; 37 }; 38 39 static int spi_clps711x_setup(struct spi_device *spi) 40 { 41 if (!spi->controller_state) { 42 int ret; 43 44 ret = devm_gpio_request(&spi->master->dev, spi->cs_gpio, 45 dev_name(&spi->master->dev)); 46 if (ret) 47 return ret; 48 49 spi->controller_state = spi; 50 } 51 52 /* We are expect that SPI-device is not selected */ 53 gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); 54 55 return 0; 56 } 57 58 static int spi_clps711x_prepare_message(struct spi_master *master, 59 struct spi_message *msg) 60 { 61 struct spi_clps711x_data *hw = spi_master_get_devdata(master); 62 struct spi_device *spi = msg->spi; 63 64 /* Setup mode for transfer */ 65 return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN, 66 (spi->mode & SPI_CPHA) ? 67 SYSCON3_ADCCKNSEN : 0); 68 } 69 70 static int spi_clps711x_transfer_one(struct spi_master *master, 71 struct spi_device *spi, 72 struct spi_transfer *xfer) 73 { 74 struct spi_clps711x_data *hw = spi_master_get_devdata(master); 75 u8 data; 76 77 clk_set_rate(hw->spi_clk, xfer->speed_hz ? : spi->max_speed_hz); 78 79 hw->len = xfer->len; 80 hw->bpw = xfer->bits_per_word; 81 hw->tx_buf = (u8 *)xfer->tx_buf; 82 hw->rx_buf = (u8 *)xfer->rx_buf; 83 84 /* Initiate transfer */ 85 data = hw->tx_buf ? *hw->tx_buf++ : 0; 86 writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio); 87 88 return 1; 89 } 90 91 static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) 92 { 93 struct spi_master *master = dev_id; 94 struct spi_clps711x_data *hw = spi_master_get_devdata(master); 95 u8 data; 96 97 /* Handle RX */ 98 data = readb(hw->syncio); 99 if (hw->rx_buf) 100 *hw->rx_buf++ = data; 101 102 /* Handle TX */ 103 if (--hw->len > 0) { 104 data = hw->tx_buf ? *hw->tx_buf++ : 0; 105 writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, 106 hw->syncio); 107 } else 108 spi_finalize_current_transfer(master); 109 110 return IRQ_HANDLED; 111 } 112 113 static int spi_clps711x_probe(struct platform_device *pdev) 114 { 115 struct spi_clps711x_data *hw; 116 struct spi_master *master; 117 struct resource *res; 118 int irq, ret; 119 120 irq = platform_get_irq(pdev, 0); 121 if (irq < 0) 122 return irq; 123 124 master = spi_alloc_master(&pdev->dev, sizeof(*hw)); 125 if (!master) 126 return -ENOMEM; 127 128 master->bus_num = -1; 129 master->mode_bits = SPI_CPHA | SPI_CS_HIGH; 130 master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); 131 master->dev.of_node = pdev->dev.of_node; 132 master->setup = spi_clps711x_setup; 133 master->prepare_message = spi_clps711x_prepare_message; 134 master->transfer_one = spi_clps711x_transfer_one; 135 136 hw = spi_master_get_devdata(master); 137 138 hw->spi_clk = devm_clk_get(&pdev->dev, NULL); 139 if (IS_ERR(hw->spi_clk)) { 140 ret = PTR_ERR(hw->spi_clk); 141 goto err_out; 142 } 143 144 hw->syscon = 145 syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon3"); 146 if (IS_ERR(hw->syscon)) { 147 ret = PTR_ERR(hw->syscon); 148 goto err_out; 149 } 150 151 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 152 hw->syncio = devm_ioremap_resource(&pdev->dev, res); 153 if (IS_ERR(hw->syncio)) { 154 ret = PTR_ERR(hw->syncio); 155 goto err_out; 156 } 157 158 /* Disable extended mode due hardware problems */ 159 regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0); 160 161 /* Clear possible pending interrupt */ 162 readl(hw->syncio); 163 164 ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0, 165 dev_name(&pdev->dev), master); 166 if (ret) 167 goto err_out; 168 169 ret = devm_spi_register_master(&pdev->dev, master); 170 if (!ret) 171 return 0; 172 173 err_out: 174 spi_master_put(master); 175 176 return ret; 177 } 178 179 static const struct of_device_id clps711x_spi_dt_ids[] = { 180 { .compatible = "cirrus,ep7209-spi", }, 181 { } 182 }; 183 MODULE_DEVICE_TABLE(of, clps711x_spi_dt_ids); 184 185 static struct platform_driver clps711x_spi_driver = { 186 .driver = { 187 .name = DRIVER_NAME, 188 .of_match_table = clps711x_spi_dt_ids, 189 }, 190 .probe = spi_clps711x_probe, 191 }; 192 module_platform_driver(clps711x_spi_driver); 193 194 MODULE_LICENSE("GPL"); 195 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 196 MODULE_DESCRIPTION("CLPS711X SPI bus driver"); 197 MODULE_ALIAS("platform:" DRIVER_NAME); 198