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