diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2012-03-14 05:48:05 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2012-03-15 05:41:01 -0400 |
commit | 49e599b8595f9d33276860c6a02e05f240c4ceca (patch) | |
tree | 50259b5e076f6551a86e7b8dcfcf96aaf3f19398 | |
parent | ec139b67ad00647239b804d6f15315b83dba9a58 (diff) |
spi: sh-hspi: control spi clock more correctly
Current sh-hspi had used platform-specific speed.
This patch remove it, and use spi_transfer specific speed.
It removes unnecessary flags from struct sh_hspi_info,
but struct sh_hspi_info is still exist, since sh-hspi needs
platform info in the future.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r-- | drivers/spi/spi-sh-hspi.c | 86 | ||||
-rw-r--r-- | include/linux/spi/sh_hspi.h | 11 |
2 files changed, 70 insertions, 27 deletions
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 42906731c40d..5784734d257d 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c | |||
@@ -22,6 +22,8 @@ | |||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | |||
26 | #include <linux/clk.h> | ||
25 | #include <linux/module.h> | 27 | #include <linux/module.h> |
26 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
27 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
@@ -50,6 +52,7 @@ struct hspi_priv { | |||
50 | void __iomem *addr; | 52 | void __iomem *addr; |
51 | struct spi_master *master; | 53 | struct spi_master *master; |
52 | struct device *dev; | 54 | struct device *dev; |
55 | struct clk *clk; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | /* | 58 | /* |
@@ -162,6 +165,59 @@ static int hspi_unprepare_transfer(struct spi_master *master) | |||
162 | return 0; | 165 | return 0; |
163 | } | 166 | } |
164 | 167 | ||
168 | static void hspi_hw_setup(struct hspi_priv *hspi, | ||
169 | struct spi_message *msg, | ||
170 | struct spi_transfer *t) | ||
171 | { | ||
172 | struct spi_device *spi = msg->spi; | ||
173 | struct device *dev = hspi->dev; | ||
174 | u32 target_rate; | ||
175 | u32 spcr, idiv_clk; | ||
176 | u32 rate, best_rate, min, tmp; | ||
177 | |||
178 | target_rate = t ? t->speed_hz : 0; | ||
179 | if (!target_rate) | ||
180 | target_rate = spi->max_speed_hz; | ||
181 | |||
182 | /* | ||
183 | * find best IDIV/CLKCx settings | ||
184 | */ | ||
185 | min = ~0; | ||
186 | best_rate = 0; | ||
187 | spcr = 0; | ||
188 | for (idiv_clk = 0x00; idiv_clk <= 0x3F; idiv_clk++) { | ||
189 | rate = clk_get_rate(hspi->clk); | ||
190 | |||
191 | /* IDIV calculation */ | ||
192 | if (idiv_clk & (1 << 5)) | ||
193 | rate /= 128; | ||
194 | else | ||
195 | rate /= 16; | ||
196 | |||
197 | /* CLKCx calculation */ | ||
198 | rate /= (((idiv_clk & 0x1F) + 1) * 2) ; | ||
199 | |||
200 | /* save best settings */ | ||
201 | tmp = abs(target_rate - rate); | ||
202 | if (tmp < min) { | ||
203 | min = tmp; | ||
204 | spcr = idiv_clk; | ||
205 | best_rate = rate; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | if (spi->mode & SPI_CPHA) | ||
210 | spcr |= 1 << 7; | ||
211 | if (spi->mode & SPI_CPOL) | ||
212 | spcr |= 1 << 6; | ||
213 | |||
214 | dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate); | ||
215 | |||
216 | hspi_write(hspi, SPCR, spcr); | ||
217 | hspi_write(hspi, SPSR, 0x0); | ||
218 | hspi_write(hspi, SPSCR, 0x1); /* master mode */ | ||
219 | } | ||
220 | |||
165 | static int hspi_transfer_one_message(struct spi_master *master, | 221 | static int hspi_transfer_one_message(struct spi_master *master, |
166 | struct spi_message *msg) | 222 | struct spi_message *msg) |
167 | { | 223 | { |
@@ -173,6 +229,8 @@ static int hspi_transfer_one_message(struct spi_master *master, | |||
173 | 229 | ||
174 | ret = 0; | 230 | ret = 0; |
175 | list_for_each_entry(t, &msg->transfers, transfer_list) { | 231 | list_for_each_entry(t, &msg->transfers, transfer_list) { |
232 | hspi_hw_setup(hspi, msg, t); | ||
233 | |||
176 | if (t->tx_buf) { | 234 | if (t->tx_buf) { |
177 | ret = hspi_push(hspi, msg, t); | 235 | ret = hspi_push(hspi, msg, t); |
178 | if (ret < 0) | 236 | if (ret < 0) |
@@ -197,28 +255,12 @@ static int hspi_setup(struct spi_device *spi) | |||
197 | { | 255 | { |
198 | struct hspi_priv *hspi = spi_master_get_devdata(spi->master); | 256 | struct hspi_priv *hspi = spi_master_get_devdata(spi->master); |
199 | struct device *dev = hspi->dev; | 257 | struct device *dev = hspi->dev; |
200 | struct sh_hspi_info *info = hspi2info(hspi); | ||
201 | u32 data; | ||
202 | 258 | ||
203 | if (8 != spi->bits_per_word) { | 259 | if (8 != spi->bits_per_word) { |
204 | dev_err(dev, "bits_per_word should be 8\n"); | 260 | dev_err(dev, "bits_per_word should be 8\n"); |
205 | return -EIO; | 261 | return -EIO; |
206 | } | 262 | } |
207 | 263 | ||
208 | /* setup first of all in under pm_runtime */ | ||
209 | data = SH_HSPI_CLK_DIVC(info->flags); | ||
210 | |||
211 | if (info->flags & SH_HSPI_FBS) | ||
212 | data |= 1 << 7; | ||
213 | if (info->flags & SH_HSPI_CLKP_HIGH) | ||
214 | data |= 1 << 6; | ||
215 | if (info->flags & SH_HSPI_IDIV_DIV128) | ||
216 | data |= 1 << 5; | ||
217 | |||
218 | hspi_write(hspi, SPCR, data); | ||
219 | hspi_write(hspi, SPSR, 0x0); | ||
220 | hspi_write(hspi, SPSCR, 0x1); /* master mode */ | ||
221 | |||
222 | dev_dbg(dev, "%s setup\n", spi->modalias); | 264 | dev_dbg(dev, "%s setup\n", spi->modalias); |
223 | 265 | ||
224 | return 0; | 266 | return 0; |
@@ -237,6 +279,7 @@ static int __devinit hspi_probe(struct platform_device *pdev) | |||
237 | struct resource *res; | 279 | struct resource *res; |
238 | struct spi_master *master; | 280 | struct spi_master *master; |
239 | struct hspi_priv *hspi; | 281 | struct hspi_priv *hspi; |
282 | struct clk *clk; | ||
240 | int ret; | 283 | int ret; |
241 | 284 | ||
242 | /* get base addr */ | 285 | /* get base addr */ |
@@ -252,12 +295,20 @@ static int __devinit hspi_probe(struct platform_device *pdev) | |||
252 | return -ENOMEM; | 295 | return -ENOMEM; |
253 | } | 296 | } |
254 | 297 | ||
298 | clk = clk_get(NULL, "shyway_clk"); | ||
299 | if (!clk) { | ||
300 | dev_err(&pdev->dev, "shyway_clk is required\n"); | ||
301 | ret = -EINVAL; | ||
302 | goto error0; | ||
303 | } | ||
304 | |||
255 | hspi = spi_master_get_devdata(master); | 305 | hspi = spi_master_get_devdata(master); |
256 | dev_set_drvdata(&pdev->dev, hspi); | 306 | dev_set_drvdata(&pdev->dev, hspi); |
257 | 307 | ||
258 | /* init hspi */ | 308 | /* init hspi */ |
259 | hspi->master = master; | 309 | hspi->master = master; |
260 | hspi->dev = &pdev->dev; | 310 | hspi->dev = &pdev->dev; |
311 | hspi->clk = clk; | ||
261 | hspi->addr = devm_ioremap(hspi->dev, | 312 | hspi->addr = devm_ioremap(hspi->dev, |
262 | res->start, resource_size(res)); | 313 | res->start, resource_size(res)); |
263 | if (!hspi->addr) { | 314 | if (!hspi->addr) { |
@@ -289,6 +340,8 @@ static int __devinit hspi_probe(struct platform_device *pdev) | |||
289 | error2: | 340 | error2: |
290 | devm_iounmap(hspi->dev, hspi->addr); | 341 | devm_iounmap(hspi->dev, hspi->addr); |
291 | error1: | 342 | error1: |
343 | clk_put(clk); | ||
344 | error0: | ||
292 | spi_master_put(master); | 345 | spi_master_put(master); |
293 | 346 | ||
294 | return ret; | 347 | return ret; |
@@ -300,6 +353,7 @@ static int __devexit hspi_remove(struct platform_device *pdev) | |||
300 | 353 | ||
301 | pm_runtime_disable(&pdev->dev); | 354 | pm_runtime_disable(&pdev->dev); |
302 | 355 | ||
356 | clk_put(hspi->clk); | ||
303 | spi_unregister_master(hspi->master); | 357 | spi_unregister_master(hspi->master); |
304 | devm_iounmap(hspi->dev, hspi->addr); | 358 | devm_iounmap(hspi->dev, hspi->addr); |
305 | 359 | ||
diff --git a/include/linux/spi/sh_hspi.h b/include/linux/spi/sh_hspi.h index 956d11288294..a1121f872ac1 100644 --- a/include/linux/spi/sh_hspi.h +++ b/include/linux/spi/sh_hspi.h | |||
@@ -17,18 +17,7 @@ | |||
17 | #ifndef SH_HSPI_H | 17 | #ifndef SH_HSPI_H |
18 | #define SH_HSPI_H | 18 | #define SH_HSPI_H |
19 | 19 | ||
20 | /* | ||
21 | * flags | ||
22 | * | ||
23 | * | ||
24 | */ | ||
25 | #define SH_HSPI_CLK_DIVC(d) (d & 0xFF) | ||
26 | |||
27 | #define SH_HSPI_FBS (1 << 8) | ||
28 | #define SH_HSPI_CLKP_HIGH (1 << 9) /* default LOW */ | ||
29 | #define SH_HSPI_IDIV_DIV128 (1 << 10) /* default div16 */ | ||
30 | struct sh_hspi_info { | 20 | struct sh_hspi_info { |
31 | u32 flags; | ||
32 | }; | 21 | }; |
33 | 22 | ||
34 | #endif | 23 | #endif |