设为首页收藏本站
查看: 10685|回复: 0

sam9x5 uboot添加i2c驱动

[复制链接]

34

主题

9

回帖

363

积分

中级会员

积分
363
conway 发表于 2015-5-13 09:25:53 | 显示全部楼层 |阅读模式
sam9x5 uboot源码中默认是没有i2c驱动的,可以参考其它atmel产品的i2c驱动写出针对sam9x5平台的驱动。
以下是基于at91rm9200平台的i2c驱动修改,以i2c0为例:
1、uboot源码中添加drivers/i2c/at91sam9x5_i2c.c
[mw_shl_code=c,true]/*
*  i2c Support for Atmel's AT91RM9200 Two-Wire Interface
*
*  (c) Rick Bronson
*
*  Borrowed heavily from original work by:
*  Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
*
*  Modified to work with u-boot by (C) 2004 Gary Jennejohn garyj@denx.de
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <common.h>

#ifdef CONFIG_HARD_I2C

#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch-at91/gpio.h>
#include <asm/arch/at91_pio.h>
#include <asm/arch/at91_pmc.h>
#include <asm/arch/io.h>

#include "at91sam9x5_i2c.h"

#define DEBUG

#ifdef DEBUG
        #define debug(fmt, arg...)        printf("MYIR_HEADER: "fmt, #arg)
#endif

/*
* Poll the i2c status register until the specified bit is set.
* Returns 0 if timed out (100 msec)
*/
static short at91_poll_status(AT91PS_TWI twi, unsigned long bit) {
        int loop_cntr = 10000;
        do {
                udelay(10);
        } while (!(twi->TWI_SR & bit) && (--loop_cntr > 0));

        return (loop_cntr > 0);
}

/*
* Generic i2c master transfer entrypoint
*
* rw == 1 means that this is a read
*/
static int
at91_xfer(unsigned char chip, unsigned int addr, int alen,
                                                unsigned char *buffer, int len, int rw)
{
        AT91PS_TWI twi = (AT91PS_TWI) AT91SAM9X5_BASE_TWI0;
        int length;
        unsigned char *buf;
        /* Set the TWI Master Mode Register */
        twi->TWI_MMR = (chip << 16) | (alen << 8)
                | ((rw == 1) ? AT91C_TWI_MREAD : 0);

        /* Set TWI Internal Address Register with first messages data field */
        if (alen > 0)
                twi->TWI_IADR = addr;

        length = len;
        buf = buffer;
        if (length && buf) {        /* sanity check */
                if (rw) {
                        twi->TWI_CR = AT91C_TWI_START;
                        while (length--) {
                                if (!length)
                                        twi->TWI_CR = AT91C_TWI_STOP;
                                /* Wait until transfer is finished */
                                if (!at91_poll_status(twi, AT91C_TWI_RXRDY)) {
                                        debug ("at91_i2c: timeout 1\n");
                                        return 1;
                                }
                                *buf++ = twi->TWI_RHR;
                        }
                        if (!at91_poll_status(twi, AT91C_TWI_TXCOMP)) {
                                debug ("at91_i2c: timeout 2\n");
                                return 1;
                        }
                } else {
                        twi->TWI_CR = AT91C_TWI_START;
                        while (length--) {
                                twi->TWI_THR = *buf++;
                                if (!length)
                                        twi->TWI_CR = AT91C_TWI_STOP;
                                if (!at91_poll_status(twi, AT91C_TWI_TXRDY)) {
                                        debug ("at91_i2c: timeout 3\n");
                                        return 1;
                                }
                        }
                        /* Wait until transfer is finished */
                        if (!at91_poll_status(twi, AT91C_TWI_TXCOMP)) {
                                debug ("at91_i2c: timeout 4\n");
                                return 1;
                        }
                }
        }
        return 0;
}

int
i2c_probe(unsigned char chip)
{
        unsigned char buffer[1];

        return at91_xfer(chip, 0, 0, buffer, 1, 1);
}

int
i2c_read (unsigned char chip, unsigned int addr, int alen,
          unsigned char *buffer, int len)
{
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
        /* we only allow one address byte */
        if (alen > 1)
                return 1;
        /* XXX assume an ATMEL AT24C16 */
        if (alen == 1) {
#if 0 /* EEPROM code already sets this correctly */
                chip |= (addr >> 8) & 0xff;
#endif
                addr = addr & 0xff;
        }
#endif
        return at91_xfer(chip, addr, alen, buffer, len, 1);
}

int
i2c_write(unsigned char chip, unsigned int addr, int alen,
          unsigned char *buffer, int len)
{
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
        int i;
        unsigned char *buf;

        /* we only allow one address byte */
        if (alen > 1)
                return 1;
        /* XXX assume an ATMEL AT24C16 */
        if (alen == 1) {
                buf = buffer;
                /* do single byte writes */
                for (i = 0; i < len; i++) {
#if 0 /* EEPROM code already sets this correctly */
                        chip |= (addr >> 8) & 0xff;
#endif
                        addr = addr & 0xff;
                        if (at91_xfer(chip, addr, alen, buf++, 1, 0))
                                return 1;
                        addr++;
                }
                return 0;
        }
#endif
        return at91_xfer(chip, addr, alen, buffer, len, 0);
}

/*
* Main initialization routine
*/
void
i2c_init(int speed, int slaveaddr)
{
        AT91PS_TWI twi = (AT91PS_TWI) AT91SAM9X5_BASE_TWI0;

        at91_set_a_periph(AT91_PIO_PORTA, 30, 0);        /* TWD0 */
        at91_set_a_periph(AT91_PIO_PORTA, 31, 1);        /* TWCK0*/

        /* Enable clock */
        at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9X5_ID_TWI0);

        twi->TWI_IDR = 0x3ff;                                /* Disable all interrupts */
        twi->TWI_CR = AT91C_TWI_SWRST;                        /* Reset peripheral */
        twi->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS;        /* Set Master mode */

        /* Here, CKDIV = 1 and CHDIV=CLDIV  ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6) */
        twi->TWI_CWGR = AT91C_TWI_CKDIV1 | AT91C_TWI_CLDIV3 | (AT91C_TWI_CLDIV3 << 8);

        debug ("Found AT91 i2c\n");
        return;
}

#endif /* CONFIG_HARD_I2C */[/mw_shl_code]

2、添加drivers/i2c/at91sam9x5_i2c.h
[mw_shl_code=applescript,true]/* ---------------------------------------------------------------------------- */
/*            ATMEL Microcontroller Software Support  -  ROUSSET        -                */
/* ---------------------------------------------------------------------------- */
/*  The software is delivered "AS IS" without warranty or condition of any        */
/*  kind, either express, implied or statutory. This includes without                */
/*  limitation any warranty or condition with respect to merchantability or        */
/*  fitness for any particular purpose, or against the infringements of                */
/*  intellectual property rights of others.                                        */
/* ---------------------------------------------------------------------------- */
/* File Name               : at91rm9200_i2c.h                                        */
/* Object               : AT91RM9200 / TWI definitions                                */
/* Generated               : AT91 SW Application Group  12/03/2002 (10:48:02)        */
/*                                                                                */
/* ---------------------------------------------------------------------------- */

#ifndef AT91SAMA5D3X_TWI_H
#define AT91SAMA5D3X_TWI_H

/* ******************************************************************************/
/*                SOFTWARE API DEFINITION         FOR Two-wire Interface                        */
/* ******************************************************************************/
#ifndef __ASSEMBLY__

typedef volatile unsigned int AT91_REG;

typedef struct _AT91S_TWI {
        AT91_REG         TWI_CR;        /* Control Register                        */
        AT91_REG         TWI_MMR;        /* Master Mode Register                        */
        AT91_REG         TWI_SMR;        /* Slave Mode Register                        */
        AT91_REG         TWI_IADR;        /* Internal Address Register                */
        AT91_REG         TWI_CWGR;        /* Clock Waveform Generator Register        */
        AT91_REG         Reserved0[3];
        AT91_REG         TWI_SR;        /* Status Register                        */
        AT91_REG         TWI_IER;        /* Interrupt Enable Register                */
        AT91_REG         TWI_IDR;        /* Interrupt Disable Register                */
        AT91_REG         TWI_IMR;        /* Interrupt Mask Register                */
        AT91_REG         TWI_RHR;        /* Receive Holding Register                */
        AT91_REG         TWI_THR;        /* Transmit Holding Register                */
        AT91_REG         Reserved1[50];
        AT91_REG         TWI_RPR;        /* Receive Pointer Register                */
        AT91_REG         TWI_RCR;        /* Receive Counter Register                */
        AT91_REG         TWI_TPR;        /* Transmit Pointer Register                */
        AT91_REG         TWI_TCR;        /* Transmit Counter Register                */
        AT91_REG         TWI_RNPR;        /* Receive Next Pointer Register        */
        AT91_REG         TWI_RNCR;        /* Receive Next Counter Register        */
        AT91_REG         TWI_TNPR;        /* Transmit Next Pointer Register        */
        AT91_REG         TWI_TNCR;        /* Transmit Next Counter Register        */
        AT91_REG         TWI_PTCR;        /* PDC Transfer Control Register        */
        AT91_REG         TWI_PTSR;        /* PDC Transfer Status Register                */
} AT91S_TWI, *AT91PS_TWI;

#endif

/* -------- TWI_CR : (TWI Offset: 0x0) TWI Control Register --------                */
#define AT91C_TWI_START (0x1 <<         0)        /* (TWI) Send a START Condition                */
#define AT91C_TWI_STOP        (0x1 <<         1)        /* (TWI) Send a STOP Condition                */
#define AT91C_TWI_MSEN        (0x1 <<         2)        /* (TWI) TWI Master Transfer Enabled        */
#define AT91C_TWI_MSDIS (0x1 <<         3)        /* (TWI) TWI Master Transfer Disabled        */
#define AT91C_TWI_SVEN        (0x1 <<         4)        /* (TWI) TWI Slave Transfer Enabled        */
#define AT91C_TWI_SVDIS (0x1 <<         5)        /* (TWI) TWI Slave Transfer Disabled        */
#define AT91C_TWI_SWRST (0x1 <<         7)        /* (TWI) Software Reset                */
/* -------- TWI_MMR : (TWI Offset: 0x4) TWI Master Mode Register --------        */
#define AT91C_TWI_IADRSZ      (0x3 <<  8) /* (TWI) Internal Device Address Size */
#define          AT91C_TWI_IADRSZ_NO          (0x0 <<  8) /* (TWI) No internal device address        */
#define          AT91C_TWI_IADRSZ_1_BYTE (0x1 <<  8) /* (TWI) One-byte internal device address */
#define          AT91C_TWI_IADRSZ_2_BYTE (0x2 <<  8) /* (TWI) Two-byte internal device address */
#define          AT91C_TWI_IADRSZ_3_BYTE (0x3 <<  8) /* (TWI) Three-byte internal device address */
#define AT91C_TWI_MREAD (0x1 << 12)        /* (TWI) Master Read Direction                */
//#define AT91C_TWI_DADR        (0x7F <<  6)        /* (TWI) Device Address                        */
#define AT91C_TWI_DADR        (0x7F <<  16)        /* (TWI) Device Address                Modified by Conway        */
/* -------- TWI_SMR : (TWI Offset: 0x8) TWI Slave Mode Register --------        */
#define AT91C_TWI_SADR        (0x7F << 16)        /* (TWI) Slave Device Address                */
/* -------- TWI_CWGR : (TWI Offset: 0x10) TWI Clock Waveform Generator Register --------        */
#define AT91C_TWI_CLDIV         (0xFF <<  0)        /* (TWI) Clock Low Divider                */
#define AT91C_TWI_CHDIV         (0xFF <<  8)        /* (TWI) Clock High Divider                */
#define AT91C_TWI_CKDIV         (0x7 << 16)        /* (TWI) Clock Divider                        */
/* -------- TWI_SR : (TWI Offset: 0x20) TWI Status Register --------                */
#define AT91C_TWI_TXCOMP (0x1 <<  0)        /* (TWI) Transmission Completed                */
#define AT91C_TWI_RXRDY         (0x1 <<  1)        /* (TWI) Receive holding register ReaDY */
#define AT91C_TWI_TXRDY         (0x1 <<  2)        /* (TWI) Transmit holding register ReaDY*/
#define AT91C_TWI_SVREAD (0x1 <<  3)        /* (TWI) Slave Read                        */
#define AT91C_TWI_SVACC         (0x1 <<  4)        /* (TWI) Slave Access                        */
#define AT91C_TWI_GCACC         (0x1 <<  5)        /* (TWI) General Call Access                */
#define AT91C_TWI_OVRE         (0x1 <<  6)        /* (TWI) Overrun Error                        */
#define AT91C_TWI_UNRE         (0x1 <<  7)        /* (TWI) Underrun Error                        */
#define AT91C_TWI_NACK         (0x1 <<  8)        /* (TWI) Not Acknowledged                */
#define AT91C_TWI_ARBLST (0x1 <<  9)        /* (TWI) Arbitration Lost                */
/* -------- TWI_IER : (TWI Offset: 0x24) TWI Interrupt Enable Register -------- */
/* -------- TWI_IDR : (TWI Offset: 0x28) TWI Interrupt Disable Register ------- */
/* -------- TWI_IMR : (TWI Offset: 0x2c) TWI Interrupt Mask Register --------        */

/*
    i2c Support for Atmel's AT91RM9200 Two-Wire Interface

    (c) Rick Bronson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef AT91_I2C_H
#define AT91_I2C_H

#define AT91C_TWI_CLOCK                100000
#define AT91C_TWI_SCLOCK        (10 * CONFIG_SYS_AT91_MAIN_CLOCK / AT91C_TWI_CLOCK)
#define AT91C_TWI_CKDIV1        (2 << 16)        /* TWI clock divider.  NOTE: see Errata #22 */

#if (AT91C_TWI_SCLOCK % 10) >= 5
#define AT91C_TWI_CLDIV2 ((AT91C_TWI_SCLOCK / 10) - 5)
#else
#define AT91C_TWI_CLDIV2 ((AT91C_TWI_SCLOCK / 10) - 6)
#endif
#define AT91C_TWI_CLDIV3 ((AT91C_TWI_CLDIV2 + (4 - AT91C_TWI_CLDIV2 % 4)) >> 2)

#define AT91C_EEPROM_I2C_ADDRESS        (0x52 << 16)

#endif        /* __ASSEMBLY__ */
#endif        /* AT91SAMA5D3X_TWI_H */[/mw_shl_code]

3、修改drivers/i2c/Makefile。添加:COBJS-$(CONFIG_AT91SAM9X5_I2C) += at91sam9x5_i2c.o
至此完成i2c驱动的添加。

回复

使用道具 举报

您需要登录后才可以回帖 登录

本版积分规则

Archiver|手机版|小黑屋|米尔科技论坛   

GMT+8, 2024-4-20 00:07 , Processed in 0.054307 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表