我是靠谱客的博主 多情手链,最近开发中收集的这篇文章主要介绍gpio模拟mdc/mdio通信,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本文主要是学习gpio模拟mdc/mdio通信。

运行环境是在ATMEL的sama5d35MCU,两个GPIO引脚模拟MDC/MDIO通信,读取百兆phy的寄存器的值。


1 #include<linux/init.h>

2 #include<linux/module.h>

3 #include<linux/kernel.h>

4 #include<linux/sched.h>

5 #include<linux/init.h>

6 #include<linux/sched.h>

7 #include<linux/completion.h>

8 #include <asm/system.h>

9 #include <linux/param.h>
 10 #include<linux/gpio.h>
 11 #include<linux/cdev.h>
 12 #include<linux/fs.h>
 13 #include<linux/device.h>
 14 #include<linux/slab.h>
 15 #include<asm/uaccess.h>
 16 #include<linux/delay.h>
 17 #include<linux/miscdevice.h>
 18
 19
 20 /* bb:bit-bang,通过gpio引脚,用软件模拟通信*/
 21
 22 #define MDIO 117
/* MDIO correspond PD21 */
 23 #define MDC 116
/* MDC correspond PD20 */
 24 #define MDIO_DELAY 250
 25 #define MDIO_READ_DELAY 350
 26
 27 /*
Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
 28  *
IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
 29  *
*/
 30 #define MII_ADDR_C45 (1<<30)
 31
 32 #define MDIO_READ 2
 33 #define MDIO_WRITE 1
 34
 35 #define MDIO_C45 (1<<15)
 36 #define MDIO_C45_ADDR (MDIO_C45 | 0)
 37 #define MDIO_C45_READ (MDIO_C45 | 3)
 38 #define MDIO_C45_WRITE (MDIO_C45 | 1)
 39
 40 #define MDIO_SETUP_TIME 10
 41 #define MDIO_HOLD_TIME 10
 42
 43
 44 //#define READ_REG 0x37
 45 //#define WRITE_REG 0x38
 46
 47
 48 #define MDIO_C45_TEST 0
 49
 50
 51 typedef struct gpio_ctrl_blk{
 52
int pin;
 53
int value;
 54 }gpio_cblk_t;
 55
 56 typedef struct phy_reg_blk{
 57
unsigned int phy_address;
 58
unsigned int reg_address;
 59
unsigned int reg_value;
 60 }phy_reg_cblk_t;
 61
 62
 63 #define MDIO_DEV_ID 't'
 64 #define READ_REG
_IOWR (MDIO_DEV_ID,0x37,phy_reg_cblk_t)
 65 #define WRITE_REG
_IOWR (MDIO_DEV_ID,0x38,phy_reg_cblk_t)
 66 static void MDC_OUT(void);
 67 static void MDIO_OUT(void);
 68 static void MDIO_IN(void);
 69 static void MDC_H(void);
 70 static void MDC_L(void);
 71 static int GET_MDIO(void);
 72 static void SET_MDIO(int val);
 73
 74
 75 /* 设置MDC为输出引脚,在MDC输出时钟之前设置 */
 76 static void MDC_OUT(void)
 77 {
 78 
gpio_cblk_t gpio_dev;
 79
gpio_dev.pin = MDC;
 80
at91_set_gpio_output(gpio_dev.pin,1);
 81 }
 82
 83 /* 设置MDIO的gpio引脚为输出引脚 */
 84 static void MDIO_OUT(void)
 85 {
 86 
gpio_cblk_t gpio_dev;
 87
gpio_dev.pin = MDIO;
 88
at91_set_gpio_output(gpio_dev.pin,1);
 89 }
 90
 91 /* 设置MDIO的gpio引脚为输入引脚 */
 92 static void MDIO_IN(void)
 93 {
 94 
gpio_cblk_t gpio_dev;
 95
gpio_dev.pin = MDIO;
 96
at91_set_gpio_input(gpio_dev.pin,1);
 97 }
 98
 99 /* MDC输出高电平,在MDC设置为输出后调用 */
100 static void MDC_H(void)
101 {
102 
gpio_cblk_t gpio_dev;
103
104
gpio_dev.pin = MDC;
105
gpio_dev.value = 1;
106 
at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
107 }
108
109 /* MDC输出低电平,在MDC设置为输出后调用 */
110 static void MDC_L(void)
111 {
112 
gpio_cblk_t gpio_dev;
113
114
gpio_dev.pin = MDC;
115
gpio_dev.value = 0;
116 
at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
117 }
118
119 /* 获得MDIO的数据,只获得一个bit */
120 static int GET_MDIO(void)
121 {
122 
gpio_cblk_t gpio_dev;
123
124
gpio_dev.pin = MDIO;
125
gpio_dev.value = at91_get_gpio_value(gpio_dev.pin);
126
127
return gpio_dev.value;
128 }
129
130 /* 设置MDIO的数据,一个bit */
131 static void SET_MDIO(int val)
132 {
133 
gpio_cblk_t gpio_dev;
134
135
gpio_dev.pin = MDIO;
136
gpio_dev.value = val;
137 
at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
138 }
139
140
141 /* MDIO发送一个bit的数据,MDIO必须已经被配置为输出 */
142 static void mdio_bb_send_bit(int val)
143 {
144 
MDC_OUT();
145 
SET_MDIO(val);
146 
ndelay(MDIO_DELAY);
147 
MDC_L();
148 
ndelay(MDIO_DELAY);
149 
MDC_H();
150 }
151
152 /*
MDIO 获取一个bit的数据,MDIO必须已经被配置为输入. */
153 static int mdio_bb_get_bit(void)
154 {
155
int value;
156
157 
MDC_OUT();
158 
ndelay(MDIO_DELAY);
159 
MDC_L();
160 
ndelay(MDIO_READ_DELAY);
161 //
ndelay(MDIO_DELAY);
162 
MDC_H();
163
164
value = GET_MDIO();
165
166
return value;
167 }
168
169
/*
170 
*
MDIO发送一个数据,MDIO 必须被配置为输出模式.
171 
*
value:要发送的数据
172 
*
bits:数据的位数
173 
*
174 
*
*/
175 static void mdio_bb_send_num(unsigned int value ,int bits)
176 {
177
int i;
178 
MDIO_OUT();
179
180
for(i = bits - 1; i >= 0; i--)
181
mdio_bb_send_bit((value >> i) & 1);
182 }
183
184
/*
185 
*
MDIO获取一个数据,MDIO 必须被配置为输入模式.
186 
*
bits:获取数据的位数
187 
*
188 
*
*/
189 static int mdio_bb_get_num(int bits)
190 {
191
int i;
192
int ret = 0;
193
for(i = bits - 1; i >= 0; i--)
194 
{
195
ret <<= 1;
196
ret |= mdio_bb_get_bit();
197 
}
198
199
return ret;
200 }
201
202
203
204 /*
Utility to send the preamble, address, and
205 *
register (common to read and write).
206 */
207 static void mdio_bb_cmd(int op,int phy,int reg)
208 {
209
int i = 0 ;
210
MDIO_OUT();
//设置MDIO引脚为输出引脚
211
212
/*发送32bit的1,这个帧前缀域不是必须的,某些物理层芯片的MDIO操作就没有这个域*/
213
for(i = 0; i < 32; i++)
214
mdio_bb_send_bit(1);
215
216
217
/* 发送开始位(01),和读操作码(10),写操作码(01)
218 
* Clause 45 操作,开始位是(00),(11)为读,(10)为写
219
*/
220
221 #if MDIO_C45_TEST
222
mdio_bb_send_bit(0);
223
if(op & MDIO_C45)
224
mdio_bb_send_bit(0);
225
else
226
mdio_bb_send_bit(1);
227
228
229 #else
230
mdio_bb_send_bit(0);
231
mdio_bb_send_bit(1);
232
233 #endif
234
mdio_bb_send_bit((op >> 1) & 1);
235
mdio_bb_send_bit((op >> 0) & 1);
236
237
mdio_bb_send_num(phy,5);
238
mdio_bb_send_num(reg,5);
239
240 }
241
242 static int mdio_bb_cmd_addr(int phy,int addr)
243 {
244
unsigned int dev_addr = (addr >> 16) & 0x1F;
245
unsigned int reg = addr & 0xFFFF;
246
247 
mdio_bb_cmd(MDIO_C45_ADDR,phy,dev_addr);
248
249
/*
send the turnaround (10) */
250
mdio_bb_send_bit(1);
251
mdio_bb_send_bit(0);
252
253
mdio_bb_send_num(reg,16);
254
255 
MDIO_IN();
256 
mdio_bb_get_bit();
257
258
return dev_addr;
259 }
260
261 void mdio_set_turnaround(void)
262 {
263
int i = 0;
264
265 
MDIO_IN();
266 
MDC_OUT();
267
for(i=0;i<2;i++)
268 
{
269 
ndelay(MDIO_DELAY);
270 
MDC_L();
271 
ndelay(MDIO_DELAY);
272 
MDC_H();
273 
}
274 }
275
276 static unsigned int mdio_bb_read(int phy,int reg)
277 {
278
unsigned int ret,i;
279
280 #if MDIO_C45_TEST
281
/* 寄存器是否满足有C45标志 */
282
if(reg & MII_ADDR_C45)
283 
{
284
reg = mdio_bb_cmd_addr(phy,reg);
285 
mdio_bb_cmd(MDIO_C45_READ,phy,reg);
286 
}
287
else
288 
mdio_bb_cmd(MDIO_READ,phy,reg);
289 #else
290 
mdio_bb_cmd(MDIO_READ,phy,reg);
291 #endif
292 
MDIO_IN();
293
//mdio_set_turnaround();
294
/*
check the turnaround bit: the PHY should be driving it to zero */
295
if(mdio_bb_get_bit() != 0)
296 
{
297
/* PHY didn't driver TA low -- flush any bits it may be trying to send*/
298
for(i = 0; i < 32; i++)
299 
mdio_bb_get_bit();
300
return 0xFFFF;
301 
}
302
303
ret = mdio_bb_get_num(16);
304 
mdio_bb_get_bit();
305
306
return ret;
307 }
308
309
310
311 static int mdio_bb_write(unsigned int phy,unsigned int reg,unsigned int val)
312 {
313 #if MDIO_C45_TEST
314
if(reg & MII_ADDR_C45)
315 
{
316
reg = mdio_bb_cmd_addr(phy,reg);
317 
mdio_bb_cmd(MDIO_C45_WRITE,phy,reg);
318 
}
319
else
320 
mdio_bb_cmd(MDIO_WRITE,phy,reg);
321 #else
322 
mdio_bb_cmd(MDIO_WRITE,phy,reg);
323 #endif
324
325
326 #if 1
327
/*
send the turnaround (10) */
328
mdio_bb_send_bit(1);
329
mdio_bb_send_bit(0);
330 #else
331 
mdio_set_turnaround();
332 #endif
333
mdio_bb_send_num(val,16);
334
335 
MDIO_IN();
336
//mdio_bb_get_bit();
337
338
return 0;
339 }
340
341
342 static int mdio_ctrl_drv_open(struct inode *inode, struct file *file )
343 {
344
return 0;
345 }
346
347 static int mdio_ctrl_drv_release(struct inode *inode, struct file *file )
348 {
349
return 0;
350 }
351
352 static long mdio_ctrl_drv_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
353 {
354 
phy_reg_cblk_t phy_reg;
355
int ret = 0;
356
357
void __user *argp = (void __user *)arg;
358
if( argp==NULL )
359 
{
360
return -EFAULT;
361 
}
362
363
if (copy_from_user(&phy_reg, argp, sizeof(phy_reg_cblk_t))) {
364
return -EFAULT;
365 
}
366
367
switch (cmd) {
368
case READ_REG:
369
phy_reg.reg_value = mdio_bb_read(phy_reg.phy_address,phy_reg.reg_address);
370
if(copy_to_user(argp,&phy_reg,sizeof(phy_reg_cblk_t)))
371 
{
372
return -EFAULT;
373 
}
374
break;
375
case WRITE_REG:
376
ret = mdio_bb_write(phy_reg.phy_address,phy_reg.reg_address,phy_reg.reg_value);
377
default:
378
return -EINVAL;
379
380 
}
381
382
return 0;
383 }
384
385 static struct file_operations mdio_ctl_drv_fileops = {
386
.owner = THIS_MODULE,
387
.open = mdio_ctrl_drv_open,
388
.unlocked_ioctl = mdio_ctrl_drv_unlocked_ioctl,
389
.release = mdio_ctrl_drv_release
390 };
391
392 static struct miscdevice mdio_dev = {
393 
MISC_DYNAMIC_MINOR,
394
"mdio_dev",
395
&mdio_ctl_drv_fileops,
396 };
397
398
399 int mdio_ctrl_drv_module_init(void)
400 {
401
int ret = 0;
402
403
ret = misc_register(&mdio_dev);
404
if(ret != 0)
405 
{
406
ret = -EFAULT;
407
return ret;
408 
}
409
printk("mdio_drv_init okn");
410
return 0;
411 }
412
413
414 void mdio_ctrl_drv_module_exit(void)
415 {
416
misc_deregister(&mdio_dev);
417
printk("mdio_drv_exit okn");
418 }
419
420
421
422 module_init(mdio_ctrl_drv_module_init);
423 module_exit(mdio_ctrl_drv_module_exit);
424 MODULE_LICENSE("GPL");
View Code

 

转载于:https://www.cnblogs.com/hjj801006/p/4864638.html

最后

以上就是多情手链为你收集整理的gpio模拟mdc/mdio通信的全部内容,希望文章能够帮你解决gpio模拟mdc/mdio通信所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部