linux设置spi时钟,linux4.1.36 SPI 时钟找不到 不生成设备 device

ca4eb5a499915c1986073e6e97fe1502.png

最初的问题是 编译内核添加了 spi 支持,配置了 board 后,加载25q64驱动不执行probe 函数。

然后发现是,spi-s3c24xx.c 中的 probe 没有执行完就退出了 没有生成 spi-master

/drivers/spi/spi-s3c24xx.c

定位在 出错

hw->clk = devm_clk_get(&pdev->dev, "spi");

if (IS_ERR(hw->clk)) {

dev_err(&pdev->dev, "No clock for device\n");

err = PTR_ERR(hw->clk);

goto err_no_pdata;

}

对应下面

struct clk *clk_get(struct device *dev, const char *con_id)

{

const char *dev_id = dev ? dev_name(dev) : NULL;

struct clk *clk;

if (dev) {

clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);

if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)

return clk;

}

return clk_get_sys(dev_id, con_id);

}

看一下 clk_get_sys(dev_id, con_id) 实现

struct clk *clk_get_sys(const char *dev_id, const char *con_id)

{

struct clk_lookup *cl;

struct clk *clk = NULL;

mutex_lock(&clocks_mutex);

cl = clk_find(dev_id, con_id);

if (!cl)

goto out;

clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);

if (IS_ERR(clk))

goto out;

if (!__clk_get(clk)) {

__clk_free_clk(clk);

cl = NULL;

goto out;

}

out:

mutex_unlock(&clocks_mutex);

return cl ? clk : ERR_PTR(-ENOENT);

}

查找 clk_find(dev_id, con_id); 函数

static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)

{

struct clk_lookup *p, *cl = NULL;

int match, best_found = 0, best_possible = 0;

if (dev_id)

best_possible += 2;

if (con_id)

best_possible += 1;

list_for_each_entry(p, &clocks, node) {

match = 0;

if (p->dev_id) {

if (!dev_id || strcmp(p->dev_id, dev_id))

continue;

match += 2;

}

if (p->con_id) {

if (!con_id || strcmp(p->con_id, con_id))

continue;

match += 1;

}

if (match > best_found) {

cl = p;

if (match != best_possible)

best_found = match;

else

break;

}

}

return cl;

}

检查 clocks 创建过程,有非常多的嵌套,就像是 俄罗期套娃。

/arch/arm/mach-s3c24xx/mach-smdk2440.c

smdk2440_init_time()

/arch/arm/mach-s3c24xx/common.c

s3c2440_init_clocks(12000000)

/drivers/clk/samsung/clk-s3c2410.c

s3c2410_common_clk_init(NULL, 12000000, 1, S3C24XX_VA_CLKPWR);

/* Register common internal clocks.  通用的内部时钟 */

samsung_clk_register_mux(ctx, s3c2410_common_muxes,

ARRAY_SIZE(s3c2410_common_muxes));

samsung_clk_register_div(ctx, s3c2410_common_dividers,

ARRAY_SIZE(s3c2410_common_dividers));

samsung_clk_register_gate(ctx, s3c2410_common_gates,

ARRAY_SIZE(s3c2410_common_gates));

if (current_soc == S3C2440 || current_soc == S3C2442) {

samsung_clk_register_div(ctx, s3c244x_common_dividers,

ARRAY_SIZE(s3c244x_common_dividers));

samsung_clk_register_gate(ctx, s3c244x_common_gates,

ARRAY_SIZE(s3c244x_common_gates));

samsung_clk_register_mux(ctx, s3c244x_common_muxes,

ARRAY_SIZE(s3c244x_common_muxes));

samsung_clk_register_fixed_factor(ctx, s3c244x_common_ffactor,

ARRAY_SIZE(s3c244x_common_ffactor));

}

/* 注册别名

* Register common aliases at the end, as some of the aliased clocks

* are SoC specific.

*/

samsung_clk_register_alias(ctx, s3c2410_common_aliases,

ARRAY_SIZE(s3c2410_common_aliases));

if (current_soc == S3C2440 || current_soc == S3C2442) {

samsung_clk_register_alias(ctx, s3c244x_common_aliases,

ARRAY_SIZE(s3c244x_common_aliases));

}

最终定位到

struct samsung_gate_clock s3c2410_common_gates[] __initdata = {

GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0),

GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0),

GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0),

GATE(PCLK_ADC, "adc", "pclk", CLKCON, 15, 0, 0),

GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 14, 0, 0),

GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 13, CLK_IGNORE_UNUSED, 0),

GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 12, 0, 0),

GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 11, 0, 0),

GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 10, 0, 0),

GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 9, 0, 0),

GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 8, 0, 0),

GATE(HCLK_USBD, "usb-device", "hclk", CLKCON, 7, 0, 0),

GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0),

GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0),

GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0),

};

/* should be added _after_ the soc-specific clocks are created */

struct samsung_clock_alias s3c2410_common_aliases[] __initdata = {

ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"),

ALIAS(PCLK_ADC, NULL, "adc"),

ALIAS(PCLK_RTC, NULL, "rtc"),

ALIAS(PCLK_PWM, NULL, "timers"),

ALIAS(HCLK_LCD, NULL, "lcd"),

ALIAS(HCLK_USBD, NULL, "usb-device"),

ALIAS(HCLK_USBH, NULL, "usb-host"),

ALIAS(UCLK, NULL, "usb-bus-host"),

ALIAS(UCLK, NULL, "usb-bus-gadget"),

ALIAS(ARMCLK, NULL, "armclk"),

ALIAS(UCLK, NULL, "uclk"),

ALIAS(HCLK, NULL, "hclk"),

ALIAS(MPLL, NULL, "mpll"),

ALIAS(FCLK, NULL, "fclk"),

ALIAS(PCLK, NULL, "watchdog"),

ALIAS(PCLK_SDI, NULL, "sdi"),

ALIAS(HCLK_NAND, NULL, "nand"),

ALIAS(PCLK_I2S, NULL, "iis"),

ALIAS(PCLK_I2C, NULL, "i2c"),

ALIAS(PCLK_SPI, NULL, "spi"), // 添加一行

};

使用新内核启动

WARNING: CPU: 0 PID: 1 at drivers/clk/clk.c:1067 clk_core_enable+0x94/0xa4()

Modules linked in:

不确定到底是何原因引起是 SPI 时钟添加的方式不对,还是spi-s3c24xx.c 中使用的不对。

先改为 i2c 启动看是否还有错误

hw->clk = devm_clk_get(&pdev->dev, "i2c");

这一次启动没有了 WARNING 信息,说明 spi-s3c24xx.c 驱动没有问题。

后来我又一想,可能 是因为内核中有 I2C 的驱动,I2C 初始化了时钟,所以 没有问题。

重新编译 内核去掉了 I2C 后,重新启动,果然还是有 WARNING 说明 spi-s3c24xx.c 有问题。

自己写一个小的驱动来测试下 SPI 时钟是否可以工作使用。

程序还不是很好用,但是可以读到 flash id ,id 好像也不太对。 后期在更新。

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8

9

10 static volatile unsigned long *gpg_con;11 static volatile unsigned long *gpg_dat;12

13 /**14 * 引脚定义15 * SPIMI GPG5 SPICLK GPG716 * SPIMO GPG6 nSSSPI GPG217 */

18

19 structspi_regs {20 unsigned long spcon; //0x59000000

21 unsigned long spsta; //0x59000004

22 unsigned long sppin; //0x59000008

23 unsigned long sppre; //0x5900000c

24 unsigned long sptdat; //0x59000010

25 unsigned long sprdat; //0x59000014

26 };27

28 static volatile struct spi_regs *spi_reg;29 static void spi_set_cs(intenable){30 //低电平选中

31 if(enable)32 {33 *gpg_dat &= ~(1<<2);34 }35 else

36 {37 *gpg_dat |= 1<<2;38 }39 }40

41 static void spi_ready(void)42 {43 while(! (spi_reg->spsta & 1));44 }45

46 static unsigned char spi_read_byte(void)47 {48 unsigned char val = 0;49 spi_reg->sptdat = 0xff;50 spi_ready();51 val = spi_reg->sprdat & 0xff;52 returnval;53 }54

55 static void spi_init(void)56 {57 struct clk *clk;58 clk = clk_get(NULL, "spi");59 if(IS_ERR(clk))60 {61 printk("get spi clock error \n");62 return;63 }64 clk_prepare_enable(clk);65 usleep_range(1000, 1100);66 //清0

67 *gpg_con &= ~(3<

69 *gpg_con |= (1<

73 spi_reg->spcon = (1<<4) | (1<<3);74 spi_reg->sppre = 2;75 }76

77 static void spi_write_byte(unsigned charval)78 {79 spi_ready();80 spi_reg->sptdat =val;81 }82

83 static void w25q_write_addr(unsigned intaddr)84 {85 spi_write_byte((addr >> 16) & 0xff);86 spi_write_byte((addr >> 8) & 0xff);87 spi_write_byte(addr & 0xff);88 }89

90 static void w25q_init(void)91 {92 spi_init();93 }94

95 static void w25q_read_id(unsigned char *factory_id, unsigned char *dev_id)96 {97 *factory_id = 0;98 *dev_id = 0;99 spi_set_cs(1);100 spi_write_byte(0x90);101 w25q_write_addr(0x0);102 *factory_id =spi_read_byte();103 *dev_id =spi_read_byte();104 spi_set_cs(0);105 }106

107 static int spi_25q_init(void)108 {109 unsigned char factory_id=0, dev_id=0;110

111 gpg_con = ioremap(0x56000060, 8);112 gpg_dat = gpg_con+1;113

114 spi_reg = ioremap(0x59000020, sizeof(structspi_regs));115 //初始化

116 w25q_init();117

118 //读ID

119 w25q_read_id(&factory_id, &dev_id);120 printk("w25q64 fid: 0x%2x devid: 0x%2x \n", factory_id, dev_id);121

122

123 return 0;124 }125

126 static void spi_25q_exit(void)127 {128 iounmap(gpg_con);129 iounmap(spi_reg);130 }131 module_init(spi_25q_init);132 module_exit(spi_25q_exit);133 MODULE_LICENSE("GPL");

cf0c852c16d029d38aace26d3605a815.png

原文:http://www.cnblogs.com/ningci/p/6607577.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值