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: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
parent
e02ddd442a
commit
b42a81ca0f
|
@ -32,6 +32,8 @@ struct s3c64xx_spi_csinfo {
|
|||
* struct s3c64xx_spi_info - SPI Controller defining structure
|
||||
* @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
|
||||
* @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.
|
||||
* @cfg_gpio: Configure pins for this SPI controller.
|
||||
* @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
|
||||
|
@ -41,6 +43,7 @@ struct s3c64xx_spi_csinfo {
|
|||
struct s3c64xx_spi_info {
|
||||
int src_clk_nr;
|
||||
char *src_clk_name;
|
||||
bool clk_from_cmu;
|
||||
|
||||
int num_cs;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
|
||||
void __iomem *regs = sdd->regs;
|
||||
u32 val;
|
||||
|
||||
/* Disable Clock */
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
|
||||
writel(val, regs + S3C64XX_SPI_CLK_CFG);
|
||||
if (sci->clk_from_cmu) {
|
||||
clk_disable(sdd->src_clk);
|
||||
} else {
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
|
||||
writel(val, regs + S3C64XX_SPI_CLK_CFG);
|
||||
}
|
||||
|
||||
/* Set Polarity and Phase */
|
||||
val = readl(regs + S3C64XX_SPI_CH_CFG);
|
||||
|
@ -441,17 +446,25 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
|||
|
||||
writel(val, regs + S3C64XX_SPI_MODE_CFG);
|
||||
|
||||
/* Configure Clock */
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
val &= ~S3C64XX_SPI_PSR_MASK;
|
||||
val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
|
||||
& S3C64XX_SPI_PSR_MASK);
|
||||
writel(val, regs + S3C64XX_SPI_CLK_CFG);
|
||||
if (sci->clk_from_cmu) {
|
||||
/* Configure Clock */
|
||||
/* There is half-multiplier before the SPI */
|
||||
clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
|
||||
/* Enable Clock */
|
||||
clk_enable(sdd->src_clk);
|
||||
} else {
|
||||
/* Configure Clock */
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
val &= ~S3C64XX_SPI_PSR_MASK;
|
||||
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);
|
||||
/* 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,
|
||||
|
@ -806,7 +819,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
|||
struct s3c64xx_spi_driver_data *sdd;
|
||||
struct s3c64xx_spi_info *sci;
|
||||
struct spi_message *msg;
|
||||
u32 psr, speed;
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
|
@ -849,31 +861,36 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
|||
}
|
||||
|
||||
/* 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 (psr == S3C64XX_SPI_PSR_MASK)
|
||||
psr--;
|
||||
if (spi->max_speed_hz > speed)
|
||||
spi->max_speed_hz = speed;
|
||||
|
||||
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;
|
||||
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);
|
||||
if (spi->max_speed_hz >= speed)
|
||||
spi->max_speed_hz = speed;
|
||||
else
|
||||
err = -EINVAL;
|
||||
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:
|
||||
|
||||
|
@ -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 */
|
||||
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);
|
||||
writel(0, regs + S3C64XX_SPI_MODE_CFG);
|
||||
writel(0, regs + S3C64XX_SPI_PACKET_CNT);
|
||||
|
|
Loading…
Reference in New Issue