📄 i2c-aa.c
字号:
/****************************************************************************** Copyright (C) 2002 Motorola GSG-China 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*******************************************************************************//************************************************************************ * File Name : i2c-aa.c * Description : * Implementation of i2c Adapter/Algorithm Driver * Auther * History: * 2002/2/7 use msgs[] * Data * ID ************************************************************************/#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/version.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/hfs_sysdep.h>#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>#include <linux/i2c-id.h>#include "i2c-aa.h"#include <asm/irq.h>#define POLLING_MODE/************************************************************************ * Globel Variable Define ************************************************************************/ static struct I2C_AA_REG *i2c_aa_reg = (struct I2C_AA_REG *)I2C_AA_REG_ADDR;#define i2c_aa_stop() i2c_aa_reg->i2cr &= ~(0x20)#define i2c_aa_repeat_start() i2c_aa_reg->i2cr |= 0x04void i2c_aa_bus_release(void);#if (LINUX_VERSION_CODE < 0x020301)static struct wait_queue *aa_wait = NULL;#elsestatic wait_queue_head_t aa_wait;#endifSINT16 __init i2c_aa_init(void);void __exit i2c_aa_cleanup(void);static void i2c_aa_inc(struct i2c_adapter *adap);static void i2c_aa_dec(struct i2c_adapter *adap);int i2c_aa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[ ], int num);int i2c_smbus_aa_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data);#ifndef POLLING_MODEstatic void i2c_aa_isr (SINT16 irq, void * dev_id, struct pt_regs * reg);#endifint i2c_aa_ioctl(struct i2c_adapter * adapter, unsigned int cmd, unsigned long arg);static struct i2c_algorithm i2c_aa_algorithm = { /* name */ "DBMX1 I2C A/A", /* id: */ I2C_ALGO_BIT, /* master_xfer:*/ i2c_aa_xfer, /* smbus_xfer: */ i2c_smbus_aa_xfer, /* slave_send: */ NULL, /* slave_recv: */ NULL, /* algo_control: */ i2c_aa_ioctl, /* functionality: */ NULL}; static struct i2c_adapter i2c_mx1_adapter = { /* name: */ "DBMX1 I2C adapter", /* id = algo->id | hwdep.struct->id */ I2C_ALGO_BIT | I2C_HW_B_SER, /* i2c_algorithm: */ &i2c_aa_algorithm, /* algo_data */ NULL, /* inc_use */ i2c_aa_inc, /* dec_use */ i2c_aa_dec, /* client_regester */ NULL, /* client_unregister */ NULL};/* return 1 : bus is idle/stop signal is detect , and Arbitration Lost * return 0 : bus is busy/start signal is detect */int i2c_aa_bus_grab(void){ unsigned int val; while(!((val = i2c_aa_reg->i2sr) & (UINT32)0x20)) { if ( val & 0x10) { return 1; } } return 0;}int i2c_aa_start(){ /* Set Master Mode and signal a start bit */ //printk(" i2c_aa_start starts \n"); i2c_aa_reg->i2cr |= 0x20; while(i2c_aa_bus_grab()){ //printk(" enter i2c_aa_bus_grab \n"); i2c_aa_stop(); i2c_aa_bus_release(); /* check IBB[I2SR:5] (I2C bus busy bit) until it is not busy *******/ while((i2c_aa_reg->i2sr) & (UINT32)0x20); /* set IEN[I2CR:7] (I2C Enable) *********************************/ i2c_aa_reg->i2cr |= (UINT32)0x80; /* Set the TXAK[I2CR:6] to disable the I2C transmit ACK *****************/ i2c_aa_reg->i2cr |= (UINT32)0x08; i2c_aa_reg->i2cr |= 0x20; } //printk(" i2c_aa_start ends \n"); return 0;}/* return when a stop signal is detect */void i2c_aa_bus_release(void){ short int i=0; int dummy; while((i2c_aa_reg->i2sr & (UINT32)0x20)&& i<1000){ i++; if (i==999){ /*Reset the module process suggested in reference manual (tahiti)*/ i2c_aa_reg->i2cr = (UINT32)0x00; i2c_aa_reg->i2cr |= (UINT32)0x0A; dummy = (UINT8)i2c_aa_reg->i2dr; i2c_aa_reg->i2sr = (UINT32)0x00; i2c_aa_reg->i2cr = (UINT32)0x00; } //printk("wait for the bus release command\n"); }}/* wait until the interrupt pending then , clear IIF[I2SR:1] */void i2c_aa_transfer_complete(void){ while(!(i2c_aa_reg->i2sr & (UINT32)0x02)); i2c_aa_reg->i2sr &= ~(UINT32)0x02;}/* wait until MX1 received the acknowledge *///This Funtion will hand the MX1, dont know why//LEOvoid i2c_aa_received_acknowledge(void){ while(i2c_aa_reg->i2sr & (UINT32)0x01);}void test(void){ unsigned int value; printk("<1>--------------------------------------\n"); value = READREG(IFDR); printk("<1>IFDR: 0x%x\n", value); value = READREG(I2CR); printk("<1>I2CR: 0x%x\n", value); value = READREG(I2SR); printk("<1>I2SR: 0x%x\n", value); printk("<1>--------------------------------------\n");}/************************************************************************ * I2C_AA Driver ************************************************************************/ void i2c_aa_inc(struct i2c_adapter *adap){ FUNC_START; MOD_INC_USE_COUNT; FUNC_END;}void i2c_aa_dec(struct i2c_adapter *adap){ FUNC_START; MOD_DEC_USE_COUNT; FUNC_END;}#ifndef POLLING_MODE#include "i2c_rw.h"#endif/*----------------------------------------------------------------------- * SINT16 __init i2c_aa_init(void) * initializes the I2C module in the DBMX1, and registers itself to the * Linux I2C system * * Parameters: * None * Return: * 0 indicates SUCCESS * -1 indicates FAILURE * --------------------------------------------------------------------*/SINT16 __init i2c_aa_init(void){ int tmp; tmp = 0; FUNC_START; /* * port enable for I2c signal * PA15 : I2C_DATA * PA16 : I2C_CLK */#ifdef POLLING_MODE MX1_REG_PTA_DDIR |= 0x00018000; MX1_REG_PTA_GIUS &= ~0x00018000;#else MX1_REG_PTA_DDIR |= 0x00018000; MX1_REG_PTA_GIUS &= ~0x00018000; //MX1_REG_PTA_GPR &= ~0x00018000; //MX1_REG_PTA_PUEN &= ~0x00018000;#endif /* Init queue */#if (LINUX_VERSION_CODE >= 0x020301) init_waitqueue_head(&aa_wait);#endif /* add the I2C adapter/algorithm driver to the linux kernel */ if (i2c_add_adapter(&i2c_mx1_adapter)) { CSI_LOC; return -1; }#ifndef POLLING_MODE /* install the I2C_AA ISR to the Linux Kernel */ tmp = request_irq(I2C_AA_IRQ, (void *)i2c_aa_isr,// SA_SHIRQ | SA_INTERRUPT, SA_INTERRUPT, "I2C_AA", "i2c_bus"); if (tmp < 0) i2c_del_adapter(&i2c_mx1_adapter); enable_irq(I2C_AA_IRQ); IOW(0x223008, I2C_AA_IRQ); // enable #endif /* Set clock Freq. */ i2c_aa_reg->ifdr = (UINT32)DEFAULT_FREQ; FUNC_END; return tmp;}/* SMbus Xfer Data */int i2c_smbus_aa_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data){ /* So we need to generate a series of msgs. In the case of writing, we need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ struct i2c_msg msg[2]; char keybuf[2]; keybuf[0] = 0; keybuf[1] = 0; msg[0].addr = addr; //msg[0].addr &= 0xFFFE; msg[0].flags = 0x00; msg[0].len = 1; msg[0].buf = &command; msg[1].addr = addr; //msg[1].addr &= 0xFFFE; msg[1].flags = I2C_M_RD; msg[1].len = 2; msg[1].buf = keybuf; printk("good\n"); i2c_transfer(adapter, msg, 2 ); data->word = keybuf[0] | (keybuf[1] << 8); return 0;#if 0 char msgbuf0[34]; char msgbuf1[34]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; printk("Enter i2c_smbus_aa_xfer\n"); msgbuf0[0] = command; switch(size) { case I2C_SMBUS_QUICK: msg[0].len = 0; /* Special case: The read/write field is used as data */ msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; num = 1; break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { /* Special case: only a read! */ msg[0].flags = I2C_M_RD | flags; num = 1; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -