diff options
Diffstat (limited to 'drivers/spi/spi-clps711x.c')
-rw-r--r-- | drivers/spi/spi-clps711x.c | 227 |
1 files changed, 107 insertions, 120 deletions
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 374ba4a48a9e..4cd62f636547 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c | |||
@@ -11,158 +11,125 @@ | |||
11 | 11 | ||
12 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
14 | #include <linux/init.h> | ||
15 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
16 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
18 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
19 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/regmap.h> | ||
20 | #include <linux/mfd/syscon.h> | ||
21 | #include <linux/mfd/syscon/clps711x.h> | ||
20 | #include <linux/spi/spi.h> | 22 | #include <linux/spi/spi.h> |
21 | #include <linux/platform_data/spi-clps711x.h> | 23 | #include <linux/platform_data/spi-clps711x.h> |
22 | 24 | ||
23 | #include <mach/hardware.h> | ||
24 | |||
25 | #define DRIVER_NAME "spi-clps711x" | 25 | #define DRIVER_NAME "spi-clps711x" |
26 | 26 | ||
27 | struct spi_clps711x_data { | 27 | #define SYNCIO_FRMLEN(x) ((x) << 8) |
28 | struct completion done; | 28 | #define SYNCIO_TXFRMEN (1 << 14) |
29 | 29 | ||
30 | struct spi_clps711x_data { | ||
31 | void __iomem *syncio; | ||
32 | struct regmap *syscon; | ||
33 | struct regmap *syscon1; | ||
30 | struct clk *spi_clk; | 34 | struct clk *spi_clk; |
31 | u32 max_speed_hz; | ||
32 | 35 | ||
33 | u8 *tx_buf; | 36 | u8 *tx_buf; |
34 | u8 *rx_buf; | 37 | u8 *rx_buf; |
35 | int count; | 38 | unsigned int bpw; |
36 | int len; | 39 | int len; |
37 | |||
38 | int chipselect[0]; | ||
39 | }; | 40 | }; |
40 | 41 | ||
41 | static int spi_clps711x_setup(struct spi_device *spi) | 42 | static int spi_clps711x_setup(struct spi_device *spi) |
42 | { | 43 | { |
43 | struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); | ||
44 | |||
45 | /* We are expect that SPI-device is not selected */ | 44 | /* We are expect that SPI-device is not selected */ |
46 | gpio_direction_output(hw->chipselect[spi->chip_select], | 45 | gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); |
47 | !(spi->mode & SPI_CS_HIGH)); | ||
48 | 46 | ||
49 | return 0; | 47 | return 0; |
50 | } | 48 | } |
51 | 49 | ||
52 | static void spi_clps711x_setup_mode(struct spi_device *spi) | 50 | static void spi_clps711x_setup_xfer(struct spi_device *spi, |
53 | { | 51 | struct spi_transfer *xfer) |
54 | /* Setup edge for transfer */ | ||
55 | if (spi->mode & SPI_CPHA) | ||
56 | clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3); | ||
57 | else | ||
58 | clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3); | ||
59 | } | ||
60 | |||
61 | static int spi_clps711x_setup_xfer(struct spi_device *spi, | ||
62 | struct spi_transfer *xfer) | ||
63 | { | 52 | { |
64 | u32 speed = xfer->speed_hz ? : spi->max_speed_hz; | 53 | struct spi_master *master = spi->master; |
65 | u8 bpw = xfer->bits_per_word; | 54 | struct spi_clps711x_data *hw = spi_master_get_devdata(master); |
66 | struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); | ||
67 | |||
68 | if (bpw != 8) { | ||
69 | dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw); | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | 55 | ||
73 | /* Setup SPI frequency divider */ | 56 | /* Setup SPI frequency divider */ |
74 | if (!speed || (speed >= hw->max_speed_hz)) | 57 | if (xfer->speed_hz >= master->max_speed_hz) |
75 | clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | | 58 | regmap_update_bits(hw->syscon1, SYSCON_OFFSET, |
76 | SYSCON1_ADCKSEL(3), SYSCON1); | 59 | SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3)); |
77 | else if (speed >= (hw->max_speed_hz / 2)) | 60 | else if (xfer->speed_hz >= (master->max_speed_hz / 2)) |
78 | clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | | 61 | regmap_update_bits(hw->syscon1, SYSCON_OFFSET, |
79 | SYSCON1_ADCKSEL(2), SYSCON1); | 62 | SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2)); |
80 | else if (speed >= (hw->max_speed_hz / 8)) | 63 | else if (xfer->speed_hz >= (master->max_speed_hz / 8)) |
81 | clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | | 64 | regmap_update_bits(hw->syscon1, SYSCON_OFFSET, |
82 | SYSCON1_ADCKSEL(1), SYSCON1); | 65 | SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1)); |
83 | else | 66 | else |
84 | clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | | 67 | regmap_update_bits(hw->syscon1, SYSCON_OFFSET, |
85 | SYSCON1_ADCKSEL(0), SYSCON1); | 68 | SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0)); |
86 | |||
87 | return 0; | ||
88 | } | 69 | } |
89 | 70 | ||
90 | static int spi_clps711x_transfer_one_message(struct spi_master *master, | 71 | static int spi_clps711x_prepare_message(struct spi_master *master, |
91 | struct spi_message *msg) | 72 | struct spi_message *msg) |
92 | { | 73 | { |
93 | struct spi_clps711x_data *hw = spi_master_get_devdata(master); | 74 | struct spi_clps711x_data *hw = spi_master_get_devdata(master); |
94 | struct spi_transfer *xfer; | 75 | struct spi_device *spi = msg->spi; |
95 | int status = 0, cs = hw->chipselect[msg->spi->chip_select]; | ||
96 | u32 data; | ||
97 | |||
98 | spi_clps711x_setup_mode(msg->spi); | ||
99 | |||
100 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | ||
101 | if (spi_clps711x_setup_xfer(msg->spi, xfer)) { | ||
102 | status = -EINVAL; | ||
103 | goto out_xfr; | ||
104 | } | ||
105 | 76 | ||
106 | gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH)); | 77 | /* Setup mode for transfer */ |
107 | 78 | return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN, | |
108 | reinit_completion(&hw->done); | 79 | (spi->mode & SPI_CPHA) ? |
109 | 80 | SYSCON3_ADCCKNSEN : 0); | |
110 | hw->count = 0; | 81 | } |
111 | hw->len = xfer->len; | ||
112 | hw->tx_buf = (u8 *)xfer->tx_buf; | ||
113 | hw->rx_buf = (u8 *)xfer->rx_buf; | ||
114 | |||
115 | /* Initiate transfer */ | ||
116 | data = hw->tx_buf ? hw->tx_buf[hw->count] : 0; | ||
117 | clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO); | ||
118 | |||
119 | wait_for_completion(&hw->done); | ||
120 | 82 | ||
121 | if (xfer->delay_usecs) | 83 | static int spi_clps711x_transfer_one(struct spi_master *master, |
122 | udelay(xfer->delay_usecs); | 84 | struct spi_device *spi, |
85 | struct spi_transfer *xfer) | ||
86 | { | ||
87 | struct spi_clps711x_data *hw = spi_master_get_devdata(master); | ||
88 | u8 data; | ||
123 | 89 | ||
124 | if (xfer->cs_change || | 90 | spi_clps711x_setup_xfer(spi, xfer); |
125 | list_is_last(&xfer->transfer_list, &msg->transfers)) | ||
126 | gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH)); | ||
127 | 91 | ||
128 | msg->actual_length += xfer->len; | 92 | hw->len = xfer->len; |
129 | } | 93 | hw->bpw = xfer->bits_per_word; |
94 | hw->tx_buf = (u8 *)xfer->tx_buf; | ||
95 | hw->rx_buf = (u8 *)xfer->rx_buf; | ||
130 | 96 | ||
131 | out_xfr: | 97 | /* Initiate transfer */ |
132 | msg->status = status; | 98 | data = hw->tx_buf ? *hw->tx_buf++ : 0; |
133 | spi_finalize_current_message(master); | 99 | writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio); |
134 | 100 | ||
135 | return 0; | 101 | return 1; |
136 | } | 102 | } |
137 | 103 | ||
138 | static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) | 104 | static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) |
139 | { | 105 | { |
140 | struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id; | 106 | struct spi_master *master = dev_id; |
141 | u32 data; | 107 | struct spi_clps711x_data *hw = spi_master_get_devdata(master); |
108 | u8 data; | ||
142 | 109 | ||
143 | /* Handle RX */ | 110 | /* Handle RX */ |
144 | data = clps_readb(SYNCIO); | 111 | data = readb(hw->syncio); |
145 | if (hw->rx_buf) | 112 | if (hw->rx_buf) |
146 | hw->rx_buf[hw->count] = (u8)data; | 113 | *hw->rx_buf++ = data; |
147 | |||
148 | hw->count++; | ||
149 | 114 | ||
150 | /* Handle TX */ | 115 | /* Handle TX */ |
151 | if (hw->count < hw->len) { | 116 | if (--hw->len > 0) { |
152 | data = hw->tx_buf ? hw->tx_buf[hw->count] : 0; | 117 | data = hw->tx_buf ? *hw->tx_buf++ : 0; |
153 | clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO); | 118 | writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, |
119 | hw->syncio); | ||
154 | } else | 120 | } else |
155 | complete(&hw->done); | 121 | spi_finalize_current_transfer(master); |
156 | 122 | ||
157 | return IRQ_HANDLED; | 123 | return IRQ_HANDLED; |
158 | } | 124 | } |
159 | 125 | ||
160 | static int spi_clps711x_probe(struct platform_device *pdev) | 126 | static int spi_clps711x_probe(struct platform_device *pdev) |
161 | { | 127 | { |
162 | int i, ret; | ||
163 | struct spi_master *master; | ||
164 | struct spi_clps711x_data *hw; | 128 | struct spi_clps711x_data *hw; |
165 | struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev); | 129 | struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev); |
130 | struct spi_master *master; | ||
131 | struct resource *res; | ||
132 | int i, irq, ret; | ||
166 | 133 | ||
167 | if (!pdata) { | 134 | if (!pdata) { |
168 | dev_err(&pdev->dev, "No platform data supplied\n"); | 135 | dev_err(&pdev->dev, "No platform data supplied\n"); |
@@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev) | |||
174 | return -EINVAL; | 141 | return -EINVAL; |
175 | } | 142 | } |
176 | 143 | ||
177 | master = spi_alloc_master(&pdev->dev, | 144 | irq = platform_get_irq(pdev, 0); |
178 | sizeof(struct spi_clps711x_data) + | 145 | if (irq < 0) |
179 | sizeof(int) * pdata->num_chipselect); | 146 | return irq; |
180 | if (!master) { | 147 | |
181 | dev_err(&pdev->dev, "SPI allocating memory error\n"); | 148 | master = spi_alloc_master(&pdev->dev, sizeof(*hw)); |
149 | if (!master) | ||
182 | return -ENOMEM; | 150 | return -ENOMEM; |
151 | |||
152 | master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) * | ||
153 | pdata->num_chipselect, GFP_KERNEL); | ||
154 | if (!master->cs_gpios) { | ||
155 | ret = -ENOMEM; | ||
156 | goto err_out; | ||
183 | } | 157 | } |
184 | 158 | ||
185 | master->bus_num = pdev->id; | 159 | master->bus_num = pdev->id; |
186 | master->mode_bits = SPI_CPHA | SPI_CS_HIGH; | 160 | master->mode_bits = SPI_CPHA | SPI_CS_HIGH; |
187 | master->bits_per_word_mask = SPI_BPW_MASK(8); | 161 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); |
188 | master->num_chipselect = pdata->num_chipselect; | 162 | master->num_chipselect = pdata->num_chipselect; |
189 | master->setup = spi_clps711x_setup; | 163 | master->setup = spi_clps711x_setup; |
190 | master->transfer_one_message = spi_clps711x_transfer_one_message; | 164 | master->prepare_message = spi_clps711x_prepare_message; |
165 | master->transfer_one = spi_clps711x_transfer_one; | ||
191 | 166 | ||
192 | hw = spi_master_get_devdata(master); | 167 | hw = spi_master_get_devdata(master); |
193 | 168 | ||
194 | for (i = 0; i < master->num_chipselect; i++) { | 169 | for (i = 0; i < master->num_chipselect; i++) { |
195 | hw->chipselect[i] = pdata->chipselect[i]; | 170 | master->cs_gpios[i] = pdata->chipselect[i]; |
196 | if (!gpio_is_valid(hw->chipselect[i])) { | 171 | ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], |
197 | dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i); | 172 | DRIVER_NAME); |
198 | ret = -EINVAL; | 173 | if (ret) { |
199 | goto err_out; | ||
200 | } | ||
201 | if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) { | ||
202 | dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i); | 174 | dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i); |
203 | ret = -EINVAL; | ||
204 | goto err_out; | 175 | goto err_out; |
205 | } | 176 | } |
206 | } | 177 | } |
@@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev) | |||
211 | ret = PTR_ERR(hw->spi_clk); | 182 | ret = PTR_ERR(hw->spi_clk); |
212 | goto err_out; | 183 | goto err_out; |
213 | } | 184 | } |
214 | hw->max_speed_hz = clk_get_rate(hw->spi_clk); | 185 | master->max_speed_hz = clk_get_rate(hw->spi_clk); |
215 | 186 | ||
216 | init_completion(&hw->done); | ||
217 | platform_set_drvdata(pdev, master); | 187 | platform_set_drvdata(pdev, master); |
218 | 188 | ||
189 | hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3"); | ||
190 | if (IS_ERR(hw->syscon)) { | ||
191 | ret = PTR_ERR(hw->syscon); | ||
192 | goto err_out; | ||
193 | } | ||
194 | |||
195 | hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1"); | ||
196 | if (IS_ERR(hw->syscon1)) { | ||
197 | ret = PTR_ERR(hw->syscon1); | ||
198 | goto err_out; | ||
199 | } | ||
200 | |||
201 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
202 | hw->syncio = devm_ioremap_resource(&pdev->dev, res); | ||
203 | if (IS_ERR(hw->syncio)) { | ||
204 | ret = PTR_ERR(hw->syncio); | ||
205 | goto err_out; | ||
206 | } | ||
207 | |||
219 | /* Disable extended mode due hardware problems */ | 208 | /* Disable extended mode due hardware problems */ |
220 | clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3); | 209 | regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0); |
221 | 210 | ||
222 | /* Clear possible pending interrupt */ | 211 | /* Clear possible pending interrupt */ |
223 | clps_readl(SYNCIO); | 212 | readl(hw->syncio); |
224 | 213 | ||
225 | ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0, | 214 | ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0, |
226 | dev_name(&pdev->dev), hw); | 215 | dev_name(&pdev->dev), master); |
227 | if (ret) { | 216 | if (ret) |
228 | dev_err(&pdev->dev, "Can't request IRQ\n"); | ||
229 | goto err_out; | 217 | goto err_out; |
230 | } | ||
231 | 218 | ||
232 | ret = devm_spi_register_master(&pdev->dev, master); | 219 | ret = devm_spi_register_master(&pdev->dev, master); |
233 | if (!ret) { | 220 | if (!ret) { |
234 | dev_info(&pdev->dev, | 221 | dev_info(&pdev->dev, |
235 | "SPI bus driver initialized. Master clock %u Hz\n", | 222 | "SPI bus driver initialized. Master clock %u Hz\n", |
236 | hw->max_speed_hz); | 223 | master->max_speed_hz); |
237 | return 0; | 224 | return 0; |
238 | } | 225 | } |
239 | 226 | ||