diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2008-07-05 04:02:46 -0400 |
---|---|---|
committer | Robert Schwebel <r.schwebel@pengutronix.de> | 2008-07-05 04:02:46 -0400 |
commit | 38a41fdf94c449c165213e4665c3f8a0d30f8aba (patch) | |
tree | cde7f6c0da8c9877736a6b66f245e163fa21c2f7 /drivers | |
parent | dbff4e9ea2e83fda89143389bfb229cb29425a32 (diff) |
IMX: introduce clock API
This patch introduces the clock API for i.MX and converts all
in-Kernel drivers to use it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/imxmmc.c | 19 | ||||
-rw-r--r-- | drivers/serial/imx.c | 25 | ||||
-rw-r--r-- | drivers/spi/spi_imx.c | 38 |
3 files changed, 67 insertions, 15 deletions
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 95f33e87a99c..ef2f6fc86541 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/mmc/host.h> | 42 | #include <linux/mmc/host.h> |
43 | #include <linux/mmc/card.h> | 43 | #include <linux/mmc/card.h> |
44 | #include <linux/delay.h> | 44 | #include <linux/delay.h> |
45 | #include <linux/clk.h> | ||
45 | 46 | ||
46 | #include <asm/dma.h> | 47 | #include <asm/dma.h> |
47 | #include <asm/io.h> | 48 | #include <asm/io.h> |
@@ -92,6 +93,8 @@ struct imxmci_host { | |||
92 | unsigned char actual_bus_width; | 93 | unsigned char actual_bus_width; |
93 | 94 | ||
94 | int prev_cmd_code; | 95 | int prev_cmd_code; |
96 | |||
97 | struct clk *clk; | ||
95 | }; | 98 | }; |
96 | 99 | ||
97 | #define IMXMCI_PEND_IRQ_b 0 | 100 | #define IMXMCI_PEND_IRQ_b 0 |
@@ -841,7 +844,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
841 | /* The prescaler is 5 for PERCLK2 equal to 96MHz | 844 | /* The prescaler is 5 for PERCLK2 equal to 96MHz |
842 | * then 96MHz / 5 = 19.2 MHz | 845 | * then 96MHz / 5 = 19.2 MHz |
843 | */ | 846 | */ |
844 | clk=imx_get_perclk2(); | 847 | clk = clk_get_rate(host->clk); |
845 | prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE; | 848 | prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE; |
846 | switch(prescaler) { | 849 | switch(prescaler) { |
847 | case 0: | 850 | case 0: |
@@ -994,6 +997,13 @@ static int imxmci_probe(struct platform_device *pdev) | |||
994 | host->res = r; | 997 | host->res = r; |
995 | host->irq = irq; | 998 | host->irq = irq; |
996 | 999 | ||
1000 | host->clk = clk_get(&pdev->dev, "perclk2"); | ||
1001 | if (IS_ERR(host->clk)) { | ||
1002 | ret = PTR_ERR(host->clk); | ||
1003 | goto out; | ||
1004 | } | ||
1005 | clk_enable(host->clk); | ||
1006 | |||
997 | imx_gpio_mode(PB8_PF_SD_DAT0); | 1007 | imx_gpio_mode(PB8_PF_SD_DAT0); |
998 | imx_gpio_mode(PB9_PF_SD_DAT1); | 1008 | imx_gpio_mode(PB9_PF_SD_DAT1); |
999 | imx_gpio_mode(PB10_PF_SD_DAT2); | 1009 | imx_gpio_mode(PB10_PF_SD_DAT2); |
@@ -1053,6 +1063,10 @@ out: | |||
1053 | imx_dma_free(host->dma); | 1063 | imx_dma_free(host->dma); |
1054 | host->dma_allocated=0; | 1064 | host->dma_allocated=0; |
1055 | } | 1065 | } |
1066 | if (host->clk) { | ||
1067 | clk_disable(host->clk); | ||
1068 | clk_put(host->clk); | ||
1069 | } | ||
1056 | } | 1070 | } |
1057 | if (mmc) | 1071 | if (mmc) |
1058 | mmc_free_host(mmc); | 1072 | mmc_free_host(mmc); |
@@ -1082,6 +1096,9 @@ static int imxmci_remove(struct platform_device *pdev) | |||
1082 | 1096 | ||
1083 | tasklet_kill(&host->tasklet); | 1097 | tasklet_kill(&host->tasklet); |
1084 | 1098 | ||
1099 | clk_disable(host->clk); | ||
1100 | clk_put(host->clk); | ||
1101 | |||
1085 | release_resource(host->res); | 1102 | release_resource(host->res); |
1086 | 1103 | ||
1087 | mmc_free_host(mmc); | 1104 | mmc_free_host(mmc); |
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 8d6cb745bd93..9e2162ebf1bb 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/tty_flip.h> | 40 | #include <linux/tty_flip.h> |
41 | #include <linux/serial_core.h> | 41 | #include <linux/serial_core.h> |
42 | #include <linux/serial.h> | 42 | #include <linux/serial.h> |
43 | #include <linux/clk.h> | ||
43 | 44 | ||
44 | #include <asm/io.h> | 45 | #include <asm/io.h> |
45 | #include <asm/irq.h> | 46 | #include <asm/irq.h> |
@@ -184,6 +185,7 @@ struct imx_port { | |||
184 | unsigned int old_status; | 185 | unsigned int old_status; |
185 | int txirq,rxirq,rtsirq; | 186 | int txirq,rxirq,rtsirq; |
186 | int have_rtscts:1; | 187 | int have_rtscts:1; |
188 | struct clk *clk; | ||
187 | }; | 189 | }; |
188 | 190 | ||
189 | /* | 191 | /* |
@@ -479,7 +481,8 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) | |||
479 | * RFDIV is set such way to satisfy requested uartclk value | 481 | * RFDIV is set such way to satisfy requested uartclk value |
480 | */ | 482 | */ |
481 | val = TXTL << 10 | RXTL; | 483 | val = TXTL << 10 | RXTL; |
482 | ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk; | 484 | ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2) |
485 | / sport->port.uartclk; | ||
483 | 486 | ||
484 | if(!ufcr_rfdiv) | 487 | if(!ufcr_rfdiv) |
485 | ufcr_rfdiv = 1; | 488 | ufcr_rfdiv = 1; |
@@ -916,7 +919,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, | |||
916 | else | 919 | else |
917 | ucfr_rfdiv = 6 - ucfr_rfdiv; | 920 | ucfr_rfdiv = 6 - ucfr_rfdiv; |
918 | 921 | ||
919 | uartclk = imx_get_perclk1(); | 922 | uartclk = clk_get_rate(sport->clk); |
920 | uartclk /= ucfr_rfdiv; | 923 | uartclk /= ucfr_rfdiv; |
921 | 924 | ||
922 | { /* | 925 | { /* |
@@ -1054,7 +1057,15 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
1054 | init_timer(&sport->timer); | 1057 | init_timer(&sport->timer); |
1055 | sport->timer.function = imx_timeout; | 1058 | sport->timer.function = imx_timeout; |
1056 | sport->timer.data = (unsigned long)sport; | 1059 | sport->timer.data = (unsigned long)sport; |
1057 | sport->port.uartclk = imx_get_perclk1(); | 1060 | |
1061 | sport->clk = clk_get(&pdev->dev, "uart_clk"); | ||
1062 | if (IS_ERR(sport->clk)) { | ||
1063 | ret = PTR_ERR(sport->clk); | ||
1064 | goto unmap; | ||
1065 | } | ||
1066 | clk_enable(sport->clk); | ||
1067 | |||
1068 | sport->port.uartclk = clk_get_rate(sport->clk); | ||
1058 | 1069 | ||
1059 | imx_ports[pdev->id] = sport; | 1070 | imx_ports[pdev->id] = sport; |
1060 | 1071 | ||
@@ -1069,6 +1080,8 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
1069 | platform_set_drvdata(pdev, &sport->port); | 1080 | platform_set_drvdata(pdev, &sport->port); |
1070 | 1081 | ||
1071 | return 0; | 1082 | return 0; |
1083 | unmap: | ||
1084 | iounmap(sport->port.membase); | ||
1072 | free: | 1085 | free: |
1073 | kfree(sport); | 1086 | kfree(sport); |
1074 | 1087 | ||
@@ -1084,8 +1097,12 @@ static int serial_imx_remove(struct platform_device *pdev) | |||
1084 | 1097 | ||
1085 | platform_set_drvdata(pdev, NULL); | 1098 | platform_set_drvdata(pdev, NULL); |
1086 | 1099 | ||
1087 | if (sport) | 1100 | if (sport) { |
1088 | uart_remove_one_port(&imx_reg, &sport->port); | 1101 | uart_remove_one_port(&imx_reg, &sport->port); |
1102 | clk_put(sport->clk); | ||
1103 | } | ||
1104 | |||
1105 | clk_disable(sport->clk); | ||
1089 | 1106 | ||
1090 | if (pdata->exit) | 1107 | if (pdata->exit) |
1091 | pdata->exit(pdev); | 1108 | pdata->exit(pdev); |
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index c730d05bfeb6..bd0729b6b6ed 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/spi/spi.h> | 29 | #include <linux/spi/spi.h> |
30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/clk.h> | ||
32 | 33 | ||
33 | #include <asm/io.h> | 34 | #include <asm/io.h> |
34 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
@@ -250,6 +251,8 @@ struct driver_data { | |||
250 | int tx_dma_needs_unmap; | 251 | int tx_dma_needs_unmap; |
251 | size_t tx_map_len; | 252 | size_t tx_map_len; |
252 | u32 dummy_dma_buf ____cacheline_aligned; | 253 | u32 dummy_dma_buf ____cacheline_aligned; |
254 | |||
255 | struct clk *clk; | ||
253 | }; | 256 | }; |
254 | 257 | ||
255 | /* Runtime state */ | 258 | /* Runtime state */ |
@@ -855,15 +858,15 @@ static irqreturn_t spi_int(int irq, void *dev_id) | |||
855 | return drv_data->transfer_handler(drv_data); | 858 | return drv_data->transfer_handler(drv_data); |
856 | } | 859 | } |
857 | 860 | ||
858 | static inline u32 spi_speed_hz(u32 data_rate) | 861 | static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate) |
859 | { | 862 | { |
860 | return imx_get_perclk2() / (4 << ((data_rate) >> 13)); | 863 | return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13)); |
861 | } | 864 | } |
862 | 865 | ||
863 | static u32 spi_data_rate(u32 speed_hz) | 866 | static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz) |
864 | { | 867 | { |
865 | u32 div; | 868 | u32 div; |
866 | u32 quantized_hz = imx_get_perclk2() >> 2; | 869 | u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2; |
867 | 870 | ||
868 | for (div = SPI_PERCLK2_DIV_MIN; | 871 | for (div = SPI_PERCLK2_DIV_MIN; |
869 | div <= SPI_PERCLK2_DIV_MAX; | 872 | div <= SPI_PERCLK2_DIV_MAX; |
@@ -947,7 +950,7 @@ static void pump_transfers(unsigned long data) | |||
947 | tmp = transfer->speed_hz; | 950 | tmp = transfer->speed_hz; |
948 | if (tmp == 0) | 951 | if (tmp == 0) |
949 | tmp = chip->max_speed_hz; | 952 | tmp = chip->max_speed_hz; |
950 | tmp = spi_data_rate(tmp); | 953 | tmp = spi_data_rate(drv_data, tmp); |
951 | u32_EDIT(control, SPI_CONTROL_DATARATE, tmp); | 954 | u32_EDIT(control, SPI_CONTROL_DATARATE, tmp); |
952 | 955 | ||
953 | writel(control, regs + SPI_CONTROL); | 956 | writel(control, regs + SPI_CONTROL); |
@@ -1109,7 +1112,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg) | |||
1109 | msg->actual_length = 0; | 1112 | msg->actual_length = 0; |
1110 | 1113 | ||
1111 | /* Per transfer setup check */ | 1114 | /* Per transfer setup check */ |
1112 | min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN); | 1115 | min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN); |
1113 | max_speed_hz = spi->max_speed_hz; | 1116 | max_speed_hz = spi->max_speed_hz; |
1114 | list_for_each_entry(trans, &msg->transfers, transfer_list) { | 1117 | list_for_each_entry(trans, &msg->transfers, transfer_list) { |
1115 | tmp = trans->bits_per_word; | 1118 | tmp = trans->bits_per_word; |
@@ -1176,6 +1179,7 @@ msg_rejected: | |||
1176 | applied and notified to the calling driver. */ | 1179 | applied and notified to the calling driver. */ |
1177 | static int setup(struct spi_device *spi) | 1180 | static int setup(struct spi_device *spi) |
1178 | { | 1181 | { |
1182 | struct driver_data *drv_data = spi_master_get_devdata(spi->master); | ||
1179 | struct spi_imx_chip *chip_info; | 1183 | struct spi_imx_chip *chip_info; |
1180 | struct chip_data *chip; | 1184 | struct chip_data *chip; |
1181 | int first_setup = 0; | 1185 | int first_setup = 0; |
@@ -1304,14 +1308,14 @@ static int setup(struct spi_device *spi) | |||
1304 | chip->n_bytes = (tmp <= 8) ? 1 : 2; | 1308 | chip->n_bytes = (tmp <= 8) ? 1 : 2; |
1305 | 1309 | ||
1306 | /* SPI datarate */ | 1310 | /* SPI datarate */ |
1307 | tmp = spi_data_rate(spi->max_speed_hz); | 1311 | tmp = spi_data_rate(drv_data, spi->max_speed_hz); |
1308 | if (tmp == SPI_CONTROL_DATARATE_BAD) { | 1312 | if (tmp == SPI_CONTROL_DATARATE_BAD) { |
1309 | status = -EINVAL; | 1313 | status = -EINVAL; |
1310 | dev_err(&spi->dev, | 1314 | dev_err(&spi->dev, |
1311 | "setup - " | 1315 | "setup - " |
1312 | "HW min speed (%d Hz) exceeds required " | 1316 | "HW min speed (%d Hz) exceeds required " |
1313 | "max speed (%d Hz)\n", | 1317 | "max speed (%d Hz)\n", |
1314 | spi_speed_hz(SPI_CONTROL_DATARATE_MIN), | 1318 | spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN), |
1315 | spi->max_speed_hz); | 1319 | spi->max_speed_hz); |
1316 | if (first_setup) | 1320 | if (first_setup) |
1317 | goto err_first_setup; | 1321 | goto err_first_setup; |
@@ -1321,7 +1325,7 @@ static int setup(struct spi_device *spi) | |||
1321 | } else { | 1325 | } else { |
1322 | u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp); | 1326 | u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp); |
1323 | /* Actual rounded max_speed_hz */ | 1327 | /* Actual rounded max_speed_hz */ |
1324 | tmp = spi_speed_hz(tmp); | 1328 | tmp = spi_speed_hz(drv_data, tmp); |
1325 | spi->max_speed_hz = tmp; | 1329 | spi->max_speed_hz = tmp; |
1326 | chip->max_speed_hz = tmp; | 1330 | chip->max_speed_hz = tmp; |
1327 | } | 1331 | } |
@@ -1352,7 +1356,7 @@ static int setup(struct spi_device *spi) | |||
1352 | chip->period & SPI_PERIOD_WAIT, | 1356 | chip->period & SPI_PERIOD_WAIT, |
1353 | spi->mode, | 1357 | spi->mode, |
1354 | spi->bits_per_word, | 1358 | spi->bits_per_word, |
1355 | spi_speed_hz(SPI_CONTROL_DATARATE_MIN), | 1359 | spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN), |
1356 | spi->max_speed_hz); | 1360 | spi->max_speed_hz); |
1357 | return status; | 1361 | return status; |
1358 | 1362 | ||
@@ -1465,6 +1469,14 @@ static int __init spi_imx_probe(struct platform_device *pdev) | |||
1465 | goto err_no_pdata; | 1469 | goto err_no_pdata; |
1466 | } | 1470 | } |
1467 | 1471 | ||
1472 | drv_data->clk = clk_get(&pdev->dev, "perclk2"); | ||
1473 | if (IS_ERR(drv_data->clk)) { | ||
1474 | dev_err(&pdev->dev, "probe - cannot get get\n"); | ||
1475 | status = PTR_ERR(drv_data->clk); | ||
1476 | goto err_no_clk; | ||
1477 | } | ||
1478 | clk_enable(drv_data->clk); | ||
1479 | |||
1468 | /* Allocate master with space for drv_data */ | 1480 | /* Allocate master with space for drv_data */ |
1469 | master = spi_alloc_master(dev, sizeof(struct driver_data)); | 1481 | master = spi_alloc_master(dev, sizeof(struct driver_data)); |
1470 | if (!master) { | 1482 | if (!master) { |
@@ -1623,6 +1635,9 @@ err_no_iores: | |||
1623 | spi_master_put(master); | 1635 | spi_master_put(master); |
1624 | 1636 | ||
1625 | err_no_pdata: | 1637 | err_no_pdata: |
1638 | clk_disable(drv_data->clk); | ||
1639 | clk_put(drv_data->clk); | ||
1640 | err_no_clk: | ||
1626 | err_no_mem: | 1641 | err_no_mem: |
1627 | return status; | 1642 | return status; |
1628 | } | 1643 | } |
@@ -1662,6 +1677,9 @@ static int __exit spi_imx_remove(struct platform_device *pdev) | |||
1662 | if (irq >= 0) | 1677 | if (irq >= 0) |
1663 | free_irq(irq, drv_data); | 1678 | free_irq(irq, drv_data); |
1664 | 1679 | ||
1680 | clk_disable(drv_data->clk); | ||
1681 | clk_put(drv_data->clk); | ||
1682 | |||
1665 | /* Release map resources */ | 1683 | /* Release map resources */ |
1666 | iounmap(drv_data->regs); | 1684 | iounmap(drv_data->regs); |
1667 | release_resource(drv_data->ioarea); | 1685 | release_resource(drv_data->ioarea); |