spi: clps711x: Simplify handling of RX & TX buffers
[deliverable/linux.git] / drivers / spi / spi-clps711x.c
CommitLineData
161b96c3
AS
1/*
2 * CLPS711X SPI bus driver
3 *
98984796 4 * Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>
161b96c3
AS
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/init.h>
15#include <linux/gpio.h>
16#include <linux/delay.h>
17#include <linux/module.h>
18#include <linux/interrupt.h>
19#include <linux/platform_device.h>
20#include <linux/spi/spi.h>
21#include <linux/platform_data/spi-clps711x.h>
22
23#include <mach/hardware.h>
24
25#define DRIVER_NAME "spi-clps711x"
26
27struct spi_clps711x_data {
28 struct completion done;
29
30 struct clk *spi_clk;
31 u32 max_speed_hz;
32
33 u8 *tx_buf;
34 u8 *rx_buf;
161b96c3
AS
35 int len;
36
37 int chipselect[0];
38};
39
40static int spi_clps711x_setup(struct spi_device *spi)
41{
42 struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
43
161b96c3
AS
44 /* We are expect that SPI-device is not selected */
45 gpio_direction_output(hw->chipselect[spi->chip_select],
46 !(spi->mode & SPI_CS_HIGH));
47
48 return 0;
49}
50
51static void spi_clps711x_setup_mode(struct spi_device *spi)
52{
53 /* Setup edge for transfer */
54 if (spi->mode & SPI_CPHA)
55 clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
56 else
57 clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
58}
59
60static int spi_clps711x_setup_xfer(struct spi_device *spi,
61 struct spi_transfer *xfer)
62{
63 u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
766ed704 64 u8 bpw = xfer->bits_per_word;
161b96c3
AS
65 struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
66
67 if (bpw != 8) {
68 dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
69 return -EINVAL;
70 }
71
72 /* Setup SPI frequency divider */
73 if (!speed || (speed >= hw->max_speed_hz))
74 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
75 SYSCON1_ADCKSEL(3), SYSCON1);
76 else if (speed >= (hw->max_speed_hz / 2))
77 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
78 SYSCON1_ADCKSEL(2), SYSCON1);
79 else if (speed >= (hw->max_speed_hz / 8))
80 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
81 SYSCON1_ADCKSEL(1), SYSCON1);
82 else
83 clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
84 SYSCON1_ADCKSEL(0), SYSCON1);
85
86 return 0;
87}
88
89static int spi_clps711x_transfer_one_message(struct spi_master *master,
90 struct spi_message *msg)
91{
92 struct spi_clps711x_data *hw = spi_master_get_devdata(master);
93 struct spi_transfer *xfer;
94 int status = 0, cs = hw->chipselect[msg->spi->chip_select];
161b96c3
AS
95
96 spi_clps711x_setup_mode(msg->spi);
97
98 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
c7a26f12
AS
99 u8 data;
100
161b96c3
AS
101 if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
102 status = -EINVAL;
103 goto out_xfr;
104 }
105
106 gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
107
16735d02 108 reinit_completion(&hw->done);
161b96c3 109
161b96c3
AS
110 hw->len = xfer->len;
111 hw->tx_buf = (u8 *)xfer->tx_buf;
112 hw->rx_buf = (u8 *)xfer->rx_buf;
113
114 /* Initiate transfer */
c7a26f12 115 data = hw->tx_buf ? *hw->tx_buf++ : 0;
161b96c3
AS
116 clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
117
118 wait_for_completion(&hw->done);
119
120 if (xfer->delay_usecs)
121 udelay(xfer->delay_usecs);
122
123 if (xfer->cs_change ||
124 list_is_last(&xfer->transfer_list, &msg->transfers))
125 gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
126
127 msg->actual_length += xfer->len;
128 }
129
130out_xfr:
131 msg->status = status;
132 spi_finalize_current_message(master);
133
134 return 0;
135}
136
137static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
138{
139 struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
c7a26f12 140 u8 data;
161b96c3
AS
141
142 /* Handle RX */
143 data = clps_readb(SYNCIO);
144 if (hw->rx_buf)
c7a26f12 145 *hw->rx_buf++ = data;
161b96c3
AS
146
147 /* Handle TX */
c7a26f12
AS
148 if (--hw->len > 0) {
149 data = hw->tx_buf ? *hw->tx_buf++ : 0;
161b96c3
AS
150 clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
151 } else
152 complete(&hw->done);
153
154 return IRQ_HANDLED;
155}
156
fd4a319b 157static int spi_clps711x_probe(struct platform_device *pdev)
161b96c3
AS
158{
159 int i, ret;
160 struct spi_master *master;
161 struct spi_clps711x_data *hw;
162 struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
163
164 if (!pdata) {
165 dev_err(&pdev->dev, "No platform data supplied\n");
166 return -EINVAL;
167 }
168
169 if (pdata->num_chipselect < 1) {
170 dev_err(&pdev->dev, "At least one CS must be defined\n");
171 return -EINVAL;
172 }
173
174 master = spi_alloc_master(&pdev->dev,
175 sizeof(struct spi_clps711x_data) +
176 sizeof(int) * pdata->num_chipselect);
177 if (!master) {
178 dev_err(&pdev->dev, "SPI allocating memory error\n");
179 return -ENOMEM;
180 }
181
182 master->bus_num = pdev->id;
183 master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
24778be2 184 master->bits_per_word_mask = SPI_BPW_MASK(8);
161b96c3
AS
185 master->num_chipselect = pdata->num_chipselect;
186 master->setup = spi_clps711x_setup;
187 master->transfer_one_message = spi_clps711x_transfer_one_message;
188
189 hw = spi_master_get_devdata(master);
190
191 for (i = 0; i < master->num_chipselect; i++) {
192 hw->chipselect[i] = pdata->chipselect[i];
193 if (!gpio_is_valid(hw->chipselect[i])) {
194 dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
195 ret = -EINVAL;
196 goto err_out;
197 }
98984796 198 if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
161b96c3
AS
199 dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
200 ret = -EINVAL;
201 goto err_out;
202 }
203 }
204
205 hw->spi_clk = devm_clk_get(&pdev->dev, "spi");
206 if (IS_ERR(hw->spi_clk)) {
207 dev_err(&pdev->dev, "Can't get clocks\n");
208 ret = PTR_ERR(hw->spi_clk);
209 goto err_out;
210 }
211 hw->max_speed_hz = clk_get_rate(hw->spi_clk);
212
213 init_completion(&hw->done);
214 platform_set_drvdata(pdev, master);
215
216 /* Disable extended mode due hardware problems */
217 clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
218
219 /* Clear possible pending interrupt */
220 clps_readl(SYNCIO);
221
222 ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
223 dev_name(&pdev->dev), hw);
224 if (ret) {
225 dev_err(&pdev->dev, "Can't request IRQ\n");
c7083790 226 goto err_out;
161b96c3
AS
227 }
228
c493fc4b 229 ret = devm_spi_register_master(&pdev->dev, master);
161b96c3
AS
230 if (!ret) {
231 dev_info(&pdev->dev,
232 "SPI bus driver initialized. Master clock %u Hz\n",
233 hw->max_speed_hz);
234 return 0;
235 }
236
237 dev_err(&pdev->dev, "Failed to register master\n");
161b96c3 238
161b96c3 239err_out:
161b96c3 240 spi_master_put(master);
161b96c3
AS
241
242 return ret;
243}
244
161b96c3
AS
245static struct platform_driver clps711x_spi_driver = {
246 .driver = {
247 .name = DRIVER_NAME,
248 .owner = THIS_MODULE,
249 },
250 .probe = spi_clps711x_probe,
161b96c3
AS
251};
252module_platform_driver(clps711x_spi_driver);
253
254MODULE_LICENSE("GPL");
255MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
256MODULE_DESCRIPTION("CLPS711X SPI bus driver");
350a9b33 257MODULE_ALIAS("platform:" DRIVER_NAME);
This page took 0.084831 seconds and 5 git commands to generate.