diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2008-01-25 00:25:31 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2008-01-26 17:32:19 -0500 |
commit | 4fb4c5582475452d3bf7c5072ef2d15ee06f7723 (patch) | |
tree | 9e75d2795deafb6601fb31c858874ebd554a4135 | |
parent | c8004a28186110657aa3e75135a6b96ebfa3e8f0 (diff) |
[POWERPC] mpc52xx_psc_spi device driver must not touch port_config and cdm
It is dangerous for an mpc52xx device driver to modify the port_config
register. If the driver is probed incorrectly, it will change the pin
IO configuration in ways which may not be compatible with the board.
port_config should be set up by the bootloader, or failing that, in
the platform setup code in arch/powerpc/platforms/52xx.
Also, modifying CDM registers directly can cause a race condition with
other drivers. Instead call a common routine to modify CDM settings.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Dragos Carp <dragos.carp@toptica.com>
-rw-r--r-- | drivers/spi/mpc52xx_psc_spi.c | 77 |
1 files changed, 2 insertions, 75 deletions
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index a3ebc632a477..253ed5682a6d 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c | |||
@@ -330,80 +330,13 @@ static void mpc52xx_psc_spi_cleanup(struct spi_device *spi) | |||
330 | 330 | ||
331 | static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) | 331 | static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) |
332 | { | 332 | { |
333 | struct device_node *np; | ||
334 | struct mpc52xx_cdm __iomem *cdm; | ||
335 | struct mpc52xx_gpio __iomem *gpio; | ||
336 | struct mpc52xx_psc __iomem *psc = mps->psc; | 333 | struct mpc52xx_psc __iomem *psc = mps->psc; |
337 | u32 ul; | ||
338 | u32 mclken_div; | 334 | u32 mclken_div; |
339 | int ret = 0; | 335 | int ret = 0; |
340 | 336 | ||
341 | #if defined(CONFIG_PPC_MERGE) | ||
342 | np = of_find_compatible_node(NULL, NULL, "mpc5200-cdm"); | ||
343 | cdm = of_iomap(np, 0); | ||
344 | of_node_put(np); | ||
345 | np = of_find_compatible_node(NULL, NULL, "mpc5200-gpio"); | ||
346 | gpio = of_iomap(np, 0); | ||
347 | of_node_put(np); | ||
348 | #else | ||
349 | cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); | ||
350 | gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE); | ||
351 | #endif | ||
352 | if (!cdm || !gpio) { | ||
353 | printk(KERN_ERR "Error mapping CDM/GPIO\n"); | ||
354 | ret = -EFAULT; | ||
355 | goto unmap_regs; | ||
356 | } | ||
357 | |||
358 | /* default sysclk is 512MHz */ | 337 | /* default sysclk is 512MHz */ |
359 | mclken_div = 0x8000 | | 338 | mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK; |
360 | (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF); | 339 | mpc52xx_set_psc_clkdiv(psc_id, mclken_div); |
361 | |||
362 | switch (psc_id) { | ||
363 | case 1: | ||
364 | ul = in_be32(&gpio->port_config); | ||
365 | ul &= 0xFFFFFFF8; | ||
366 | ul |= 0x00000006; | ||
367 | out_be32(&gpio->port_config, ul); | ||
368 | out_be16(&cdm->mclken_div_psc1, mclken_div); | ||
369 | ul = in_be32(&cdm->clk_enables); | ||
370 | ul |= 0x00000020; | ||
371 | out_be32(&cdm->clk_enables, ul); | ||
372 | break; | ||
373 | case 2: | ||
374 | ul = in_be32(&gpio->port_config); | ||
375 | ul &= 0xFFFFFF8F; | ||
376 | ul |= 0x00000060; | ||
377 | out_be32(&gpio->port_config, ul); | ||
378 | out_be16(&cdm->mclken_div_psc2, mclken_div); | ||
379 | ul = in_be32(&cdm->clk_enables); | ||
380 | ul |= 0x00000040; | ||
381 | out_be32(&cdm->clk_enables, ul); | ||
382 | break; | ||
383 | case 3: | ||
384 | ul = in_be32(&gpio->port_config); | ||
385 | ul &= 0xFFFFF0FF; | ||
386 | ul |= 0x00000600; | ||
387 | out_be32(&gpio->port_config, ul); | ||
388 | out_be16(&cdm->mclken_div_psc3, mclken_div); | ||
389 | ul = in_be32(&cdm->clk_enables); | ||
390 | ul |= 0x00000080; | ||
391 | out_be32(&cdm->clk_enables, ul); | ||
392 | break; | ||
393 | case 6: | ||
394 | ul = in_be32(&gpio->port_config); | ||
395 | ul &= 0xFF8FFFFF; | ||
396 | ul |= 0x00700000; | ||
397 | out_be32(&gpio->port_config, ul); | ||
398 | out_be16(&cdm->mclken_div_psc6, mclken_div); | ||
399 | ul = in_be32(&cdm->clk_enables); | ||
400 | ul |= 0x00000010; | ||
401 | out_be32(&cdm->clk_enables, ul); | ||
402 | break; | ||
403 | default: | ||
404 | ret = -EINVAL; | ||
405 | goto unmap_regs; | ||
406 | } | ||
407 | 340 | ||
408 | /* Reset the PSC into a known state */ | 341 | /* Reset the PSC into a known state */ |
409 | out_8(&psc->command, MPC52xx_PSC_RST_RX); | 342 | out_8(&psc->command, MPC52xx_PSC_RST_RX); |
@@ -427,12 +360,6 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) | |||
427 | 360 | ||
428 | mps->bits_per_word = 8; | 361 | mps->bits_per_word = 8; |
429 | 362 | ||
430 | unmap_regs: | ||
431 | if (cdm) | ||
432 | iounmap(cdm); | ||
433 | if (gpio) | ||
434 | iounmap(gpio); | ||
435 | |||
436 | return ret; | 363 | return ret; |
437 | } | 364 | } |
438 | 365 | ||