前天编写S3C24x0芯片的ADC驱动。其实很简单,参考别人的驱动,把以前的驱动模板改改就好了。可是写好后没使用成功。测来测去,最后发现对ADC的寄存器根本无法写入,只能读出。郁闷!!一开始以为是我用的赋值语句不对,参考我的驱动学习文档,试了一圈,问题依旧!郁闷了整整两天之后,在网上看到有人也遇到了2410的外设寄存器无法赋值的情况,最后发现是时钟问题。受此启发,我回想起了以前看的Linux的SPI驱动,里面有以下语句: hw->clk = clk_get(&pdev->dev, 'spi'); if (IS_ERR(hw->clk)) { dev_err(&pdev->dev, 'No clock for device '); err = PTR_ERR(hw->clk); goto err_no_clk; }
/* for the moment, permanently enable the clock */
clk_enable(hw->clk);
当时也没怎么在意,后悔啊!之后我在DAC驱动上加了类似的语句,参考了别人的2410触摸屏驱动,将'spi'改为'adc' 。实验成功!
--------------------------------------------------------------------------------
三星的S3C24x0处理器为了实现低功耗,增加对外设的时钟和电源的管理。具体的内容请看芯片手册的《7. Clock & Power Management》这一章。虽然芯片启动时默认这些外设的时钟是使能的,但在Linux下,启动时为了节能考虑,将部分时钟关闭了。如果没有使能这些时钟,就会出现无法对外设寄存器写操作的情况。Linux中时钟使能部分的源码主要有: /include/asm-arm/plat-s3c24xx/clock.h /include/asm-arm/arch-s3c2410/regs-clock.h /arch/arm/mach-s3c2410/clock.c
参考这些源码,就可以大致知道Linux是如何操作S3C24x0处理器的外设时钟的。
特别是/arch/arm/mach-s3c2410/clock.c中的以下数据对编程有所帮助:
/* standard clock definitions */
static struct clk init_clocks_disable[] = { { .name = 'nand', .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_NAND, }, { .name = 'sdi', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_SDI, }, { .name = 'adc', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_ADC, }, { .name = 'i2c', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_IIC, }, { .name = 'iis', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_IIS, }, { .name = 'spi', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_SPI, } };
static struct clk init_clocks[] = { { .name = 'lcd', .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_LCDC, }, { .name = 'gpio', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_GPIO, }, { .name = 'usb-host', .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_USBH, }, { .name = 'usb-device', .id = -1, .parent = &clk_h, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_USBD, }, { .name = 'timers', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_PWMT, }, { .name = 'uart', .id = 0, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART0, }, { .name = 'uart', .id = 1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART1, }, { .name = 'uart', .id = 2, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART2, }, { .name = 'rtc', .id = -1, .parent = &clk_p, .enable = s3c2410_clkcon_enable, .ctrlbit = S3C2410_CLKCON_RTC, }, { .name = 'watchdog', .id = -1, .parent = &clk_p, .ctrlbit = 0, }, { .name = 'usb-bus-host', .id = -1, .parent = &clk_usb_bus, }, { .name = 'usb-bus-gadget', .id = -1, .parent = &clk_usb_bus, }, };
|