|
@@ -113,7 +113,6 @@
|
|
|
#define SSP_CR0_MASK_CSS_ST (0x1FUL << 16)
|
|
|
#define SSP_CR0_MASK_FRF_ST (0x3UL << 21)
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
* SSP Control Register 0 - SSP_CR1
|
|
|
*/
|
|
@@ -283,7 +282,6 @@
|
|
|
|
|
|
#define SPI_POLLING_TIMEOUT 1000
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
* The type of reading going on on this chip
|
|
|
*/
|
|
@@ -749,7 +747,6 @@ static void readwriter(struct pl022 *pl022)
|
|
|
*/
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* next_transfer - Move to the Next transfer in the current spi message
|
|
|
* @pl022: SSP driver private data structure
|
|
@@ -1016,14 +1013,14 @@ static int configure_dma(struct pl022 *pl022)
|
|
|
dmaengine_slave_config(txchan, &tx_conf);
|
|
|
|
|
|
/* Create sglists for the transfers */
|
|
|
- pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1;
|
|
|
+ pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE);
|
|
|
dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages);
|
|
|
|
|
|
- ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_KERNEL);
|
|
|
+ ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC);
|
|
|
if (ret)
|
|
|
goto err_alloc_rx_sg;
|
|
|
|
|
|
- ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_KERNEL);
|
|
|
+ ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC);
|
|
|
if (ret)
|
|
|
goto err_alloc_tx_sg;
|
|
|
|
|
@@ -1531,8 +1528,7 @@ static void pump_messages(struct work_struct *work)
|
|
|
/* Initial message state */
|
|
|
pl022->cur_msg->state = STATE_START;
|
|
|
pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next,
|
|
|
- struct spi_transfer,
|
|
|
- transfer_list);
|
|
|
+ struct spi_transfer, transfer_list);
|
|
|
|
|
|
/* Setup the SPI using the per chip configuration */
|
|
|
pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
|
|
@@ -1551,7 +1547,6 @@ static void pump_messages(struct work_struct *work)
|
|
|
do_interrupt_dma_transfer(pl022);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static int __init init_queue(struct pl022 *pl022)
|
|
|
{
|
|
|
INIT_LIST_HEAD(&pl022->queue);
|
|
@@ -1560,8 +1555,8 @@ static int __init init_queue(struct pl022 *pl022)
|
|
|
pl022->running = false;
|
|
|
pl022->busy = false;
|
|
|
|
|
|
- tasklet_init(&pl022->pump_transfers,
|
|
|
- pump_transfers, (unsigned long)pl022);
|
|
|
+ tasklet_init(&pl022->pump_transfers, pump_transfers,
|
|
|
+ (unsigned long)pl022);
|
|
|
|
|
|
INIT_WORK(&pl022->pump_messages, pump_messages);
|
|
|
pl022->workqueue = create_singlethread_workqueue(
|
|
@@ -1572,7 +1567,6 @@ static int __init init_queue(struct pl022 *pl022)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static int start_queue(struct pl022 *pl022)
|
|
|
{
|
|
|
unsigned long flags;
|
|
@@ -1595,7 +1589,6 @@ static int start_queue(struct pl022 *pl022)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static int stop_queue(struct pl022 *pl022)
|
|
|
{
|
|
|
unsigned long flags;
|
|
@@ -1791,71 +1784,70 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int calculate_effective_freq(struct pl022 *pl022,
|
|
|
- int freq,
|
|
|
- struct ssp_clock_params *clk_freq)
|
|
|
+static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
|
|
|
+{
|
|
|
+ return rate / (cpsdvsr * (1 + scr));
|
|
|
+}
|
|
|
+
|
|
|
+static int calculate_effective_freq(struct pl022 *pl022, int freq, struct
|
|
|
+ ssp_clock_params * clk_freq)
|
|
|
{
|
|
|
/* Lets calculate the frequency parameters */
|
|
|
- u16 cpsdvsr = 2;
|
|
|
- u16 scr = 0;
|
|
|
- bool freq_found = false;
|
|
|
- u32 rate;
|
|
|
- u32 max_tclk;
|
|
|
- u32 min_tclk;
|
|
|
+ u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN;
|
|
|
+ u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0,
|
|
|
+ best_scr = 0, tmp, found = 0;
|
|
|
|
|
|
rate = clk_get_rate(pl022->clk);
|
|
|
/* cpsdvscr = 2 & scr 0 */
|
|
|
- max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN)));
|
|
|
+ max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN);
|
|
|
/* cpsdvsr = 254 & scr = 255 */
|
|
|
- min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX)));
|
|
|
-
|
|
|
- if ((freq <= max_tclk) && (freq >= min_tclk)) {
|
|
|
- while (cpsdvsr <= CPSDVR_MAX && !freq_found) {
|
|
|
- while (scr <= SCR_MAX && !freq_found) {
|
|
|
- if ((rate /
|
|
|
- (cpsdvsr * (1 + scr))) > freq)
|
|
|
- scr += 1;
|
|
|
- else {
|
|
|
- /*
|
|
|
- * This bool is made true when
|
|
|
- * effective frequency >=
|
|
|
- * target frequency is found
|
|
|
- */
|
|
|
- freq_found = true;
|
|
|
- if ((rate /
|
|
|
- (cpsdvsr * (1 + scr))) != freq) {
|
|
|
- if (scr == SCR_MIN) {
|
|
|
- cpsdvsr -= 2;
|
|
|
- scr = SCR_MAX;
|
|
|
- } else
|
|
|
- scr -= 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (!freq_found) {
|
|
|
- cpsdvsr += 2;
|
|
|
- scr = SCR_MIN;
|
|
|
- }
|
|
|
- }
|
|
|
- if (cpsdvsr != 0) {
|
|
|
- dev_dbg(&pl022->adev->dev,
|
|
|
- "SSP Effective Frequency is %u\n",
|
|
|
- (rate / (cpsdvsr * (1 + scr))));
|
|
|
- clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
|
|
|
- clk_freq->scr = (u8) (scr & 0xFF);
|
|
|
- dev_dbg(&pl022->adev->dev,
|
|
|
- "SSP cpsdvsr = %d, scr = %d\n",
|
|
|
- clk_freq->cpsdvsr, clk_freq->scr);
|
|
|
- }
|
|
|
- } else {
|
|
|
+ min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
|
|
|
+
|
|
|
+ if (!((freq <= max_tclk) && (freq >= min_tclk))) {
|
|
|
dev_err(&pl022->adev->dev,
|
|
|
"controller data is incorrect: out of range frequency");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * best_freq will give closest possible available rate (<= requested
|
|
|
+ * freq) for all values of scr & cpsdvsr.
|
|
|
+ */
|
|
|
+ while ((cpsdvsr <= CPSDVR_MAX) && !found) {
|
|
|
+ while (scr <= SCR_MAX) {
|
|
|
+ tmp = spi_rate(rate, cpsdvsr, scr);
|
|
|
+
|
|
|
+ if (tmp > freq)
|
|
|
+ scr++;
|
|
|
+ /*
|
|
|
+ * If found exact value, update and break.
|
|
|
+ * If found more closer value, update and continue.
|
|
|
+ */
|
|
|
+ else if ((tmp == freq) || (tmp > best_freq)) {
|
|
|
+ best_freq = tmp;
|
|
|
+ best_cpsdvsr = cpsdvsr;
|
|
|
+ best_scr = scr;
|
|
|
+
|
|
|
+ if (tmp == freq)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ scr++;
|
|
|
+ }
|
|
|
+ cpsdvsr += 2;
|
|
|
+ scr = SCR_MIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
|
|
|
+ clk_freq->scr = (u8) (best_scr & 0xFF);
|
|
|
+ dev_dbg(&pl022->adev->dev,
|
|
|
+ "SSP Target Frequency is: %u, Effective Frequency is %u\n",
|
|
|
+ freq, best_freq);
|
|
|
+ dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n",
|
|
|
+ clk_freq->cpsdvsr, clk_freq->scr);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
* A piece of default chip info unless the platform
|
|
|
* supplies it.
|
|
@@ -1873,7 +1865,6 @@ static const struct pl022_config_chip pl022_default_chip_info = {
|
|
|
.cs_control = null_cs_control,
|
|
|
};
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* pl022_setup - setup function registered to SPI master framework
|
|
|
* @spi: spi device which is requesting setup
|
|
@@ -1950,7 +1941,6 @@ static int pl022_setup(struct spi_device *spi)
|
|
|
goto err_config_params;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
status = verify_controller_parameters(pl022, chip_info);
|
|
|
if (status) {
|
|
|
dev_err(&spi->dev, "controller data is incorrect");
|
|
@@ -2090,7 +2080,8 @@ static int pl022_setup(struct spi_device *spi)
|
|
|
}
|
|
|
SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
|
|
|
SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
|
|
|
- SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
|
|
|
+ SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD,
|
|
|
+ 3);
|
|
|
|
|
|
/* Save controller_state */
|
|
|
spi_set_ctldata(spi, chip);
|
|
@@ -2116,7 +2107,6 @@ static void pl022_cleanup(struct spi_device *spi)
|
|
|
kfree(chip);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static int __devinit
|
|
|
pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
|
|
{
|
|
@@ -2242,7 +2232,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
|
|
err_start_queue:
|
|
|
err_init_queue:
|
|
|
destroy_queue(pl022);
|
|
|
- pl022_dma_remove(pl022);
|
|
|
+ if (platform_info->enable_dma)
|
|
|
+ pl022_dma_remove(pl022);
|
|
|
+
|
|
|
free_irq(adev->irq[0], pl022);
|
|
|
err_no_irq:
|
|
|
clk_unprepare(pl022->clk);
|
|
@@ -2277,7 +2269,9 @@ pl022_remove(struct amba_device *adev)
|
|
|
if (destroy_queue(pl022) != 0)
|
|
|
dev_err(&adev->dev, "queue remove failed\n");
|
|
|
load_ssp_default_config(pl022);
|
|
|
- pl022_dma_remove(pl022);
|
|
|
+ if (pl022->master_info->enable_dma)
|
|
|
+ pl022_dma_remove(pl022);
|
|
|
+
|
|
|
free_irq(adev->irq[0], pl022);
|
|
|
clk_disable(pl022->clk);
|
|
|
clk_unprepare(pl022->clk);
|
|
@@ -2364,7 +2358,6 @@ static struct vendor_data vendor_arm = {
|
|
|
.loopback = true,
|
|
|
};
|
|
|
|
|
|
-
|
|
|
static struct vendor_data vendor_st = {
|
|
|
.fifodepth = 32,
|
|
|
.max_bpw = 32,
|
|
@@ -2419,9 +2412,9 @@ static struct amba_id pl022_ids[] = {
|
|
|
* and 32 locations deep TX/RX FIFO but no extended
|
|
|
* CR0/CR1 register
|
|
|
*/
|
|
|
- .id = 0x00080023,
|
|
|
- .mask = 0xffffffff,
|
|
|
- .data = &vendor_st_pl023,
|
|
|
+ .id = 0x00080023,
|
|
|
+ .mask = 0xffffffff,
|
|
|
+ .data = &vendor_st_pl023,
|
|
|
},
|
|
|
{
|
|
|
.id = 0x10080023,
|
|
@@ -2441,19 +2434,16 @@ static struct amba_driver pl022_driver = {
|
|
|
.remove = __devexit_p(pl022_remove),
|
|
|
};
|
|
|
|
|
|
-
|
|
|
static int __init pl022_init(void)
|
|
|
{
|
|
|
return amba_driver_register(&pl022_driver);
|
|
|
}
|
|
|
-
|
|
|
subsys_initcall(pl022_init);
|
|
|
|
|
|
static void __exit pl022_exit(void)
|
|
|
{
|
|
|
amba_driver_unregister(&pl022_driver);
|
|
|
}
|
|
|
-
|
|
|
module_exit(pl022_exit);
|
|
|
|
|
|
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
|