注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

蒙奇D小豌豆的博客

蒙奇D小豌豆的学习记录

 
 
 

日志

 
 

i2c设备驱动legacy写法  

2010-04-08 22:41:10|  分类: others |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在上一篇的文章中的i2c驱动中 我们可以有另外一种写法 legacy,该方法不需要改变dts文件

先给出文件mpc8572_sfp_phy.h 上一篇文章页适用的

#ifndef __MPC8572_SFP_PHY_H
#define __MPC8572_SFP_PHY_H

#define M1111_BMCR 0x00

#define M1111_BMCR_ANRESTART 0x0200   /* Auto negotiation restart */
#define M1111_BMCR_ANENABLE 0x1000    /* Enable auto negotiation */
#define M1111_BMCR_SW_RESET 0x8000  /* Software reset */

#define M1111_BMSR 0x01
#define M1111_BMSR_LSTATUS 0x0004  /* Link status */
#define M1111_BMSR_ANEGCOMPLETE 0x0020  /* Auto-negotiation complete   */

#define M1111_ADVERTISE 0x04

#define M1111_LPA 0x05

#define M1111_ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
#define M1111_ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
#define M1111_ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
#define M1111_ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
#define M1111_ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
#define M1111_ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
#define M1111_ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
#define M1111_ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
#define M1111_ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
#define M1111_ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
#define M1111_ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymetric pause     */

#define M1111_CTRL1000 0x09

/* 1000BASE-T Control register */
#define M1111_ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
#define M1111_ADVERTISE_1000HALF      0x0100  /* Advertise 1000BASE-T half duplex */

#define M1111_PHY_SCR 0x10

#define M1111_PHY_STATUS 0x11

#define M1111_PHY_STATUS_1000 0x8000
#define M1111_PHY_STATUS_100 0x4000
#define M1111_PHY_STATUS_SPD_MASK 0xc000
#define M1111_PHY_STATUS_FULLDUPLEX 0x2000
#define M1111_PHY_LINK 0X0400

#define M1111_PHY_EXT_SR 0x1b

#define M1111_HWCFG_MODE_MASK 0xf
#define M1111_HWCFG_MODE_SGMII_NO_CLK 0x4
#define M1111_HWCFG_FIBER_COPPER_AUTO 0x8000

/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
#define SPEED_10 10
#define SPEED_100 100
#define SPEED_1000 1000

/* Duplex, half or full. */
#define DUPLEX_HALF  0x00
#define DUPLEX_FULL  0x01

/* 
 bit 1  bit 0 SFPx
  0       0  SFP1 
  0       1  SFP2
  1       0  SFP3
  1       1  SFP4  
*/
#define SFP_SELECT_REG 0xffdf0000  /* sfp select register */
#define SFP_LED_CTL 0xffdf0001   /* sfp led control register */

#define SFP_PHY0_ID "1-0056"

/* APIs for i2c node phy */
int m1111_phy_read(struct i2c_client  *client, u8 addr);
int m1111_phy_write(struct i2c_client *client, u8 addr, u16 value);
int m1111_read_status(struct i2c_client *client, struct phy_device *phydev);
int m1111_config_aneg_done(struct i2c_client *client);
//void m1111_rxtx_blink(struct phy_device *phydev);
void m1111_led_red(struct phy_device *phydev);

struct i2c_client *get_sfp_i2c_client(void);
#endif

 

 

i2c驱动legacy写法

#include <linux/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#include <linux/sysctl.h>
#include <linux/proc_fs.h>

#include <linux/mutex.h>//wx
#include <linux/i2c.h>
#include "mpc8572_sfp_phy.h"

/*
 * Functions declaration
 */


static int phy_attach_adapter(struct i2c_adapter *adapter);
static int phy_detach_client(struct i2c_client *client);


/*give the addr of the i2c *///通过下面的结构  告知内核我们 i2c设备的地址是多少 (0x56) 
static unsigned short normal_i2c[] = { 0x56, I2C_CLIENT_END };
static unsigned short probe[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
static unsigned short ignore[2] = { I2C_CLIENT_END , I2C_CLIENT_END };

static struct i2c_client_address_data addr_data = {   
 .normal_i2c=normal_i2c,     
 .probe=probe,     
 .ignore=ignore,     
 //.forces  = forces,     
};


static void __iomem *sfp_select;
static void __iomem *sfp_led_ctl;

struct mutex   mutex_sfp_select;//wx
struct mutex   mutex_sfp_led_ctl;//wx

 

/*  
 i2c phy read interface
 return a 16-bit unsigned word received from device
*/
int m1111_phy_read(struct i2c_client *client, u8 addr)
{
 int val;
 unsigned short ret;

 val = i2c_smbus_read_word_data(client,addr);
 if( val < 0 )
  return val;

 /* Conversion from big-endian to little-endian */
 ret = ( ( val >> 8) & 0x00ff ) | ( ( val << 8) & 0xff00);
 return ret;
}

/*
 i2c phy write interface
 16-bit word being written
*/
int m1111_phy_write(struct i2c_client *client, u8 addr, u16 value)
{
 u16 tmp;
 
 /* Conversion from big-endian to little-endian */
 tmp = ( ( value >> 8) & 0x00ff ) | ( ( value<< 8) & 0xff00);
 return i2c_smbus_write_word_data(client,addr,tmp);
}

int m1111_config_aneg_done(struct i2c_client *client)
{
 int retval;

 retval = m1111_phy_read(client, M1111_BMSR);

 return ( retval < 0 ) ? retval : ( retval & M1111_BMSR_ANEGCOMPLETE );
}

static int m1111_update_link(struct i2c_client *client, struct phy_device *phydev)
{
 int status;
 unsigned short tmp;
 
 /* do a fake read */
 status = m1111_phy_read(client, M1111_BMSR);
 if(status < 0)
  return status;

 /* read link and auto-negotiation status */
 status = m1111_phy_read(client, M1111_BMSR);
 if(status < 0)
  return status;

 if(status & M1111_BMSR_LSTATUS) {
  phydev->link = 1;
 }else{
  phydev->link = 0;
 }

 /* phy has link we turn led green */
 if( phydev->link ){
  mutex_lock(&mutex_sfp_led_ctl);//wx
  tmp = in_8(sfp_led_ctl);

  if(!strcmp(phydev->attached_dev->name,"eth0"))
   tmp = (tmp & 0xfc) | 0x02;
  else if( !strcmp(phydev->attached_dev->name,"eth1"))
   tmp = ( tmp & 0xf3 ) | 0x08;
  else if( !strcmp(phydev->attached_dev->name,"eth2"))
   tmp = ( tmp & 0xcf ) | 0x20;
  else
   tmp = (tmp & 0x3f ) | 0x80;

  out_8(sfp_led_ctl, tmp);
  mutex_unlock(&mutex_sfp_led_ctl);//wx

 }
 /* phy link down we turn led red */
 else{
  mutex_lock(&mutex_sfp_led_ctl);//wx
  tmp = in_8(sfp_led_ctl);

  if(!strcmp(phydev->attached_dev->name,"eth0"))
   tmp = (tmp & 0xfc) | 0x01;
  else if( !strcmp(phydev->attached_dev->name,"eth1"))
   tmp = ( tmp & 0xf3 ) | 0x04;
  else if( !strcmp(phydev->attached_dev->name,"eth2"))
   tmp = ( tmp & 0xcf ) | 0x10;
  else
   tmp = (tmp & 0x3f ) | 0x40;

  out_8(sfp_led_ctl, tmp);
  mutex_unlock(&mutex_sfp_led_ctl);//wx

 }
 
 return status;
 
}

void m1111_led_red(struct phy_device *phydev)
{
 unsigned short tmp;

 mutex_lock(&mutex_sfp_led_ctl);//wx
 tmp = in_8(sfp_led_ctl);

 if(!strcmp(phydev->attached_dev->name,"eth0"))
  tmp = (tmp & 0xfc) | 0x01;
 else if( !strcmp(phydev->attached_dev->name,"eth1"))
  tmp = ( tmp & 0xf3 ) | 0x04;
 else if( !strcmp(phydev->attached_dev->name,"eth2"))
  tmp = ( tmp & 0xcf ) | 0x10;
 else
  tmp = (tmp & 0x3f ) | 0x40;

 out_8(sfp_led_ctl, tmp);
 mutex_unlock(&mutex_sfp_led_ctl);//wx

 phydev->state = PHY_NOLINK;
}

static int sfp_phy_compare_id(struct device *dev, void *data)
{
 return strcmp((char *)data, dev->bus_id) ? 0 : 1;
}


struct i2c_client *get_sfp_i2c_client(void)
{
 struct bus_type *bus = &i2c_bus_type;
 struct device *d;

 struct i2c_client *sfp_phy_client;
 
 d = bus_find_device(bus, NULL, (void *)SFP_PHY0_ID , sfp_phy_compare_id);
 
 if(d){
  sfp_phy_client = dev_get_drvdata(d);
 }else {
  return ERR_PTR(-ENODEV);
 }

 //printk("in the get sfp_phy_client  i2c_client is name  %s, driver name is %s\n",sfp_phy_client->name,sfp_phy_client->driver->driver.name);
 return sfp_phy_client;
 
}

int m1111_read_status(struct i2c_client *client, struct phy_device *phydev)
{
 int adv;
 int err;
 int lpa;
 int status = 0;
 unsigned short tmp;


 if( NULL == client){
  printk("Error, no client attached!\n");
  return -ENODEV;
 }
 /*
 *  first need to know which port we are operating on, then we write epld reg
 * to configure the corresponding port
 */
 mutex_lock(&mutex_sfp_select);//wx
 tmp = in_8(sfp_select);

 if(!strcmp(phydev->attached_dev->name,"eth0"))
  tmp &= 0xfc;
 else if( !strcmp(phydev->attached_dev->name,"eth1"))
  tmp = ( tmp & 0xfc ) | 0x01;
 else if( !strcmp(phydev->attached_dev->name,"eth2"))
  tmp = ( tmp & 0xfc ) | 0x02;
 else
  tmp = (tmp & 0xfc ) | 0x03;

 out_8(sfp_select, tmp);
 mutex_unlock(&mutex_sfp_select);//wx

 err = m1111_update_link(client, phydev);
 if(err < 0)
  return err;
 
 status = m1111_phy_read(client, M1111_PHY_STATUS);
 
 if(status < 0)
  return status;
 
 lpa = m1111_phy_read(client, M1111_LPA);
 if(lpa < 0)
  return lpa;

 adv = m1111_phy_read(client, M1111_ADVERTISE);
 if(adv < 0)
  return adv;

 lpa &= adv;

 if(status & M1111_PHY_STATUS_FULLDUPLEX){
  phydev->duplex= DUPLEX_FULL;
 }else{
  phydev->duplex = DUPLEX_HALF;
 }

 status = status & M1111_PHY_STATUS_SPD_MASK;
 switch (status) {
  case M1111_PHY_STATUS_1000:
   phydev->speed= SPEED_1000;
   break;

  case M1111_PHY_STATUS_100:
   phydev->speed = SPEED_100;
   break;

  default:
   phydev->speed = SPEED_10;
   break;
 } 
 
 return 0;
}


static struct i2c_driver phy_driver = {
 .driver = {
  .name = "phy_88e1111",
 },
 .attach_adapter = phy_attach_adapter,
 .detach_client = phy_detach_client,
};

static int phy_detect(struct i2c_adapter *adapter, int address, int kind)
{
 struct i2c_client *client;
 //struct ds1337_data *data;
 int err = 0;
 const char *name = "";

 printk("now we are in the phy_detect...........\n");
 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
         I2C_FUNC_I2C))
  goto exit;

 if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
  err = -ENOMEM;
  goto exit;
 }
 
 //new_client = &data->client;
 i2c_set_clientdata(client, client);
 client->addr = address;
 client->adapter = adapter;
 client->driver = &phy_driver;
 client->flags = 0;


 name = "88e1111";

 /* We can fill in the remaining client fields */
 strlcpy(client->name, name, I2C_NAME_SIZE);

 /* Tell the I2C layer a new client has arrived */
 if ((err = i2c_attach_client(client)))
  goto exit_free;
 /*init something*/
 mutex_init(&mutex_sfp_select);//wx
 mutex_init(&mutex_sfp_led_ctl);//wx

 dev_info(&client->dev,"chip found\n");


 sfp_select = ioremap(SFP_SELECT_REG,1);
 if( NULL == sfp_select){
  printk("ioremap failed\n");
  err= -ENOMEM;
  goto exit;
 }

 sfp_led_ctl = ioremap(SFP_LED_CTL,1);
 if( NULL == sfp_led_ctl) {
  err = -ENOMEM;
  goto exit;
 }

 return 0;
 
 exit_free:
 kfree(client);
 exit:
  return err;

}


static int phy_attach_adapter(struct i2c_adapter *adapter)
{
 printk("now we are in the phy_attach_adapter...........\n");
 return i2c_probe(adapter, &addr_data, phy_detect);
}


static int phy_detach_client(struct i2c_client *client)
{
 int err;
 
 if(sfp_led_ctl)
  iounmap(sfp_led_ctl);
 
 if(sfp_select)
  iounmap(sfp_select);

 if ((err = i2c_detach_client(client)))
  return err;

 kfree(client);

 return 0;
}


static int __init phy88_init(void)
{
 return i2c_add_driver(&phy_driver);
}

static void __exit phy88_exit(void)
{
 i2c_del_driver(&phy_driver);
}

MODULE_AUTHOR("wenxu<wenx05124561@163.com>");
MODULE_DESCRIPTION("phy i2c driver");
MODULE_LICENSE("GPL");

 

module_init(phy88_init);
module_exit(phy88_exit);

 

  评论这张
 
阅读(802)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018