|
@@ -29,6 +29,7 @@
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
|
|
+#include <linux/clk.h>
|
|
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/irq.h>
|
|
@@ -250,6 +251,8 @@ struct driver_data {
|
|
int tx_dma_needs_unmap;
|
|
int tx_dma_needs_unmap;
|
|
size_t tx_map_len;
|
|
size_t tx_map_len;
|
|
u32 dummy_dma_buf ____cacheline_aligned;
|
|
u32 dummy_dma_buf ____cacheline_aligned;
|
|
|
|
+
|
|
|
|
+ struct clk *clk;
|
|
};
|
|
};
|
|
|
|
|
|
/* Runtime state */
|
|
/* Runtime state */
|
|
@@ -855,15 +858,15 @@ static irqreturn_t spi_int(int irq, void *dev_id)
|
|
return drv_data->transfer_handler(drv_data);
|
|
return drv_data->transfer_handler(drv_data);
|
|
}
|
|
}
|
|
|
|
|
|
-static inline u32 spi_speed_hz(u32 data_rate)
|
|
|
|
|
|
+static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate)
|
|
{
|
|
{
|
|
- return imx_get_perclk2() / (4 << ((data_rate) >> 13));
|
|
|
|
|
|
+ return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13));
|
|
}
|
|
}
|
|
|
|
|
|
-static u32 spi_data_rate(u32 speed_hz)
|
|
|
|
|
|
+static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz)
|
|
{
|
|
{
|
|
u32 div;
|
|
u32 div;
|
|
- u32 quantized_hz = imx_get_perclk2() >> 2;
|
|
|
|
|
|
+ u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2;
|
|
|
|
|
|
for (div = SPI_PERCLK2_DIV_MIN;
|
|
for (div = SPI_PERCLK2_DIV_MIN;
|
|
div <= SPI_PERCLK2_DIV_MAX;
|
|
div <= SPI_PERCLK2_DIV_MAX;
|
|
@@ -947,7 +950,7 @@ static void pump_transfers(unsigned long data)
|
|
tmp = transfer->speed_hz;
|
|
tmp = transfer->speed_hz;
|
|
if (tmp == 0)
|
|
if (tmp == 0)
|
|
tmp = chip->max_speed_hz;
|
|
tmp = chip->max_speed_hz;
|
|
- tmp = spi_data_rate(tmp);
|
|
|
|
|
|
+ tmp = spi_data_rate(drv_data, tmp);
|
|
u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);
|
|
u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);
|
|
|
|
|
|
writel(control, regs + SPI_CONTROL);
|
|
writel(control, regs + SPI_CONTROL);
|
|
@@ -1109,7 +1112,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
|
|
msg->actual_length = 0;
|
|
msg->actual_length = 0;
|
|
|
|
|
|
/* Per transfer setup check */
|
|
/* Per transfer setup check */
|
|
- min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN);
|
|
|
|
|
|
+ min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN);
|
|
max_speed_hz = spi->max_speed_hz;
|
|
max_speed_hz = spi->max_speed_hz;
|
|
list_for_each_entry(trans, &msg->transfers, transfer_list) {
|
|
list_for_each_entry(trans, &msg->transfers, transfer_list) {
|
|
tmp = trans->bits_per_word;
|
|
tmp = trans->bits_per_word;
|
|
@@ -1176,6 +1179,7 @@ msg_rejected:
|
|
applied and notified to the calling driver. */
|
|
applied and notified to the calling driver. */
|
|
static int setup(struct spi_device *spi)
|
|
static int setup(struct spi_device *spi)
|
|
{
|
|
{
|
|
|
|
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
|
|
struct spi_imx_chip *chip_info;
|
|
struct spi_imx_chip *chip_info;
|
|
struct chip_data *chip;
|
|
struct chip_data *chip;
|
|
int first_setup = 0;
|
|
int first_setup = 0;
|
|
@@ -1304,14 +1308,14 @@ static int setup(struct spi_device *spi)
|
|
chip->n_bytes = (tmp <= 8) ? 1 : 2;
|
|
chip->n_bytes = (tmp <= 8) ? 1 : 2;
|
|
|
|
|
|
/* SPI datarate */
|
|
/* SPI datarate */
|
|
- tmp = spi_data_rate(spi->max_speed_hz);
|
|
|
|
|
|
+ tmp = spi_data_rate(drv_data, spi->max_speed_hz);
|
|
if (tmp == SPI_CONTROL_DATARATE_BAD) {
|
|
if (tmp == SPI_CONTROL_DATARATE_BAD) {
|
|
status = -EINVAL;
|
|
status = -EINVAL;
|
|
dev_err(&spi->dev,
|
|
dev_err(&spi->dev,
|
|
"setup - "
|
|
"setup - "
|
|
"HW min speed (%d Hz) exceeds required "
|
|
"HW min speed (%d Hz) exceeds required "
|
|
"max speed (%d Hz)\n",
|
|
"max speed (%d Hz)\n",
|
|
- spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
|
|
|
|
|
|
+ spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
|
|
spi->max_speed_hz);
|
|
spi->max_speed_hz);
|
|
if (first_setup)
|
|
if (first_setup)
|
|
goto err_first_setup;
|
|
goto err_first_setup;
|
|
@@ -1321,7 +1325,7 @@ static int setup(struct spi_device *spi)
|
|
} else {
|
|
} else {
|
|
u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);
|
|
u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);
|
|
/* Actual rounded max_speed_hz */
|
|
/* Actual rounded max_speed_hz */
|
|
- tmp = spi_speed_hz(tmp);
|
|
|
|
|
|
+ tmp = spi_speed_hz(drv_data, tmp);
|
|
spi->max_speed_hz = tmp;
|
|
spi->max_speed_hz = tmp;
|
|
chip->max_speed_hz = tmp;
|
|
chip->max_speed_hz = tmp;
|
|
}
|
|
}
|
|
@@ -1352,7 +1356,7 @@ static int setup(struct spi_device *spi)
|
|
chip->period & SPI_PERIOD_WAIT,
|
|
chip->period & SPI_PERIOD_WAIT,
|
|
spi->mode,
|
|
spi->mode,
|
|
spi->bits_per_word,
|
|
spi->bits_per_word,
|
|
- spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
|
|
|
|
|
|
+ spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
|
|
spi->max_speed_hz);
|
|
spi->max_speed_hz);
|
|
return status;
|
|
return status;
|
|
|
|
|
|
@@ -1465,6 +1469,14 @@ static int __init spi_imx_probe(struct platform_device *pdev)
|
|
goto err_no_pdata;
|
|
goto err_no_pdata;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ drv_data->clk = clk_get(&pdev->dev, "perclk2");
|
|
|
|
+ if (IS_ERR(drv_data->clk)) {
|
|
|
|
+ dev_err(&pdev->dev, "probe - cannot get get\n");
|
|
|
|
+ status = PTR_ERR(drv_data->clk);
|
|
|
|
+ goto err_no_clk;
|
|
|
|
+ }
|
|
|
|
+ clk_enable(drv_data->clk);
|
|
|
|
+
|
|
/* Allocate master with space for drv_data */
|
|
/* Allocate master with space for drv_data */
|
|
master = spi_alloc_master(dev, sizeof(struct driver_data));
|
|
master = spi_alloc_master(dev, sizeof(struct driver_data));
|
|
if (!master) {
|
|
if (!master) {
|
|
@@ -1623,6 +1635,9 @@ err_no_iores:
|
|
spi_master_put(master);
|
|
spi_master_put(master);
|
|
|
|
|
|
err_no_pdata:
|
|
err_no_pdata:
|
|
|
|
+ clk_disable(drv_data->clk);
|
|
|
|
+ clk_put(drv_data->clk);
|
|
|
|
+err_no_clk:
|
|
err_no_mem:
|
|
err_no_mem:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
@@ -1662,6 +1677,9 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
|
|
if (irq >= 0)
|
|
if (irq >= 0)
|
|
free_irq(irq, drv_data);
|
|
free_irq(irq, drv_data);
|
|
|
|
|
|
|
|
+ clk_disable(drv_data->clk);
|
|
|
|
+ clk_put(drv_data->clk);
|
|
|
|
+
|
|
/* Release map resources */
|
|
/* Release map resources */
|
|
iounmap(drv_data->regs);
|
|
iounmap(drv_data->regs);
|
|
release_resource(drv_data->ioarea);
|
|
release_resource(drv_data->ioarea);
|