Commit b42a81ca authored by Jassi Brar's avatar Jassi Brar Committed by Grant Likely

spi/s3c64xx: Consider the clk_from_cmu flag

Newer SoCs have the SPI clock scaling control in platform's
clock management unit. Inorder for such SoCs to work, we need
to check the flag clk_from_cmu before making any clock changes.
Signed-off-by: default avatarJassi Brar <jassi.brar@samsung.com>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent e02ddd44
...@@ -32,6 +32,8 @@ struct s3c64xx_spi_csinfo { ...@@ -32,6 +32,8 @@ struct s3c64xx_spi_csinfo {
* struct s3c64xx_spi_info - SPI Controller defining structure * struct s3c64xx_spi_info - SPI Controller defining structure
* @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field. * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
* @src_clk_name: Platform name of the corresponding clock. * @src_clk_name: Platform name of the corresponding clock.
* @clk_from_cmu: If the SPI clock/prescalar control block is present
* by the platform's clock-management-unit and not in SPI controller.
* @num_cs: Number of CS this controller emulates. * @num_cs: Number of CS this controller emulates.
* @cfg_gpio: Configure pins for this SPI controller. * @cfg_gpio: Configure pins for this SPI controller.
* @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6 * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
...@@ -41,6 +43,7 @@ struct s3c64xx_spi_csinfo { ...@@ -41,6 +43,7 @@ struct s3c64xx_spi_csinfo {
struct s3c64xx_spi_info { struct s3c64xx_spi_info {
int src_clk_nr; int src_clk_nr;
char *src_clk_name; char *src_clk_name;
bool clk_from_cmu;
int num_cs; int num_cs;
......
...@@ -399,13 +399,18 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, ...@@ -399,13 +399,18 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
{ {
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs; void __iomem *regs = sdd->regs;
u32 val; u32 val;
/* Disable Clock */ /* Disable Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG); if (sci->clk_from_cmu) {
val &= ~S3C64XX_SPI_ENCLK_ENABLE; clk_disable(sdd->src_clk);
writel(val, regs + S3C64XX_SPI_CLK_CFG); } else {
val = readl(regs + S3C64XX_SPI_CLK_CFG);
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
writel(val, regs + S3C64XX_SPI_CLK_CFG);
}
/* Set Polarity and Phase */ /* Set Polarity and Phase */
val = readl(regs + S3C64XX_SPI_CH_CFG); val = readl(regs + S3C64XX_SPI_CH_CFG);
...@@ -441,17 +446,25 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) ...@@ -441,17 +446,25 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
writel(val, regs + S3C64XX_SPI_MODE_CFG); writel(val, regs + S3C64XX_SPI_MODE_CFG);
/* Configure Clock */ if (sci->clk_from_cmu) {
val = readl(regs + S3C64XX_SPI_CLK_CFG); /* Configure Clock */
val &= ~S3C64XX_SPI_PSR_MASK; /* There is half-multiplier before the SPI */
val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
& S3C64XX_SPI_PSR_MASK); /* Enable Clock */
writel(val, regs + S3C64XX_SPI_CLK_CFG); clk_enable(sdd->src_clk);
} else {
/* Enable Clock */ /* Configure Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG); val = readl(regs + S3C64XX_SPI_CLK_CFG);
val |= S3C64XX_SPI_ENCLK_ENABLE; val &= ~S3C64XX_SPI_PSR_MASK;
writel(val, regs + S3C64XX_SPI_CLK_CFG); val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
& S3C64XX_SPI_PSR_MASK);
writel(val, regs + S3C64XX_SPI_CLK_CFG);
/* Enable Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG);
val |= S3C64XX_SPI_ENCLK_ENABLE;
writel(val, regs + S3C64XX_SPI_CLK_CFG);
}
} }
static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
...@@ -806,7 +819,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi) ...@@ -806,7 +819,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
struct s3c64xx_spi_driver_data *sdd; struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci; struct s3c64xx_spi_info *sci;
struct spi_message *msg; struct spi_message *msg;
u32 psr, speed;
unsigned long flags; unsigned long flags;
int err = 0; int err = 0;
...@@ -849,32 +861,37 @@ static int s3c64xx_spi_setup(struct spi_device *spi) ...@@ -849,32 +861,37 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
} }
/* Check if we can provide the requested rate */ /* Check if we can provide the requested rate */
speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */ if (!sci->clk_from_cmu) {
u32 psr, speed;
if (spi->max_speed_hz > speed)
spi->max_speed_hz = speed; /* Max possible */
speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);
psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
psr &= S3C64XX_SPI_PSR_MASK; if (spi->max_speed_hz > speed)
if (psr == S3C64XX_SPI_PSR_MASK) spi->max_speed_hz = speed;
psr--;
psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
psr &= S3C64XX_SPI_PSR_MASK;
if (psr == S3C64XX_SPI_PSR_MASK)
psr--;
speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
if (spi->max_speed_hz < speed) {
if (psr+1 < S3C64XX_SPI_PSR_MASK) {
psr++;
} else {
err = -EINVAL;
goto setup_exit;
}
}
speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
if (spi->max_speed_hz < speed) { if (spi->max_speed_hz >= speed)
if (psr+1 < S3C64XX_SPI_PSR_MASK) { spi->max_speed_hz = speed;
psr++; else
} else {
err = -EINVAL; err = -EINVAL;
goto setup_exit;
}
} }
speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
if (spi->max_speed_hz >= speed)
spi->max_speed_hz = speed;
else
err = -EINVAL;
setup_exit: setup_exit:
/* setup() returns with device de-selected */ /* setup() returns with device de-selected */
...@@ -896,7 +913,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) ...@@ -896,7 +913,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
/* Disable Interrupts - we use Polling if not DMA mode */ /* Disable Interrupts - we use Polling if not DMA mode */
writel(0, regs + S3C64XX_SPI_INT_EN); writel(0, regs + S3C64XX_SPI_INT_EN);
writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT, if (!sci->clk_from_cmu)
writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
regs + S3C64XX_SPI_CLK_CFG); regs + S3C64XX_SPI_CLK_CFG);
writel(0, regs + S3C64XX_SPI_MODE_CFG); writel(0, regs + S3C64XX_SPI_MODE_CFG);
writel(0, regs + S3C64XX_SPI_PACKET_CNT); writel(0, regs + S3C64XX_SPI_PACKET_CNT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment