📄 i2c-mp200.c
字号:
/* * File Name : linux/drivers/i2c/busses/i2c-mp200.c * Function : i2c * Release Version : Ver 1.01 * Release Date : 2006/03/21 * * Copyright (C) NEC Electronics Corporation 2005-2006 * * * 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 Free Softwere Foundation; either version 2 * of 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 warrnty 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. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/version.h>#include <linux/i2c.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/device.h>#include <linux/moduleparam.h>#include <linux/interrupt.h>#include <linux/ioctl.h>#include "i2c-mp200.h"/* ----- global defines ----------------------------------------------- */#define DEFAULT_CLOCK 100000 /* default 100KHz */#define MAX_MESSAGES 65536 /* max number of messages *//* ----- global variables --------------------------------------------- */static wait_queue_head_t i2c_wait;static volatile int i2c_pending;static spinlock_t i2c_lock = SPIN_LOCK_UNLOCKED;static spinlock_t i2c_irq_lock = SPIN_LOCK_UNLOCKED;static int i2c_arbls;/* ----- module parameters -------------------------------------------- */static int clock;static int irq = INT_IIC; /* polling mode if irq = 0 */static int i2c_scan = 0; /* have a look at what's hanging 'round *//* ----- Forward declarations ----------------------------------------- */static int mp200_i2c_xfer(struct i2c_adapter *, struct i2c_msg[], int);static int mp200_i2c_rxbytes(struct i2c_adapter *, struct i2c_msg *, int);static int mp200_i2c_suspend(struct device *dev, u32 state, u32 level);static int mp200_i2c_resume(struct device *dev, u32 level);/* ----- Utility functions -------------------------------------------- */static void mp200_setup_iiccl0_iicx0(struct i2c_adapter *adap){ u16 bit = 0x0; i2c_ctrl_t *ctrl = (i2c_ctrl_t *) adap->algo_data;#ifdef I2C_DEBUG printk(KERN_INFO "mp200_setup_iiccl0_iicx0(): IICCL0: %04x, IICX0: %04x\n", inw(I2C_REG_IICCL0), inw(I2C_REG_IICX0));#endif /* mode */ if (ctrl->smc == I2C_SMC_HIGH_SPEED) { /* High-speed mode(Maximum transfer rate 250kbit/s) */ bit |= I2C_BIT_SMC0; } /* else Nomal mode(Maximum transfer rate 70kbit/s)(default) */ /* digital filter */ if (ctrl->dfc == I2C_DFC_ON) { /* digital filter ON */ bit |= I2C_BIT_DFC0; } /* else digital filter OFF */ /* clock speed */ switch (ctrl->clo) { case I2C_CLO_4: /* if standard mode, 6.4MHz support if high-speed mode, 6.4MHz support */ bit |= I2C_BIT_CLO1; bit |= I2C_BIT_CLO0; break; case I2C_CLO_3: /* if standard mode, 4.19MHz <= Fxx <= 8.38MHz if high-speed mode, 4.00MHz <= Fxx <= 8.38MHz */ bit |= I2C_BIT_CLO1; break; case I2C_CLO_2: /* if standard mode, 4.19MHz <= Fxx <= 8.38MHz if high-speed mode, 4.00MHz <= Fxx <= 8.38MHz */ bit |= I2C_BIT_CLO0; break; case I2C_CLO_1: default: /* if standard mode, 2.00MHz <= Fxx <= 4.19MHz (default) if high-speed mode, 4.00MHz <= Fxx <= 8.38MHz */ break; } outw(bit, I2C_REG_IICCL0); if (ctrl->clx == I2C_CLX_HIGH) { outw(I2C_BIT_CLX0, I2C_REG_IICX0); } else { outw(0x0, I2C_REG_IICX0); }#ifdef I2C_DEBUG printk(KERN_INFO "mp200_setup_iiccl0_iicx0(): IICCL0: %04x, IICX0: %04x\n", inw(I2C_REG_IICCL0), inw(I2C_REG_IICX0));#endif}static void mp200_init(struct i2c_adapter *adap){ if (inw(I2C_REG_IICC0) & I2C_BIT_IICE0) { spin_lock(&i2c_lock); outw(0, I2C_REG_IICC0); spin_unlock(&i2c_lock); mdelay(10); } mp200_setup_iiccl0_iicx0(adap); outw((I2C_BIT_STCEN | I2C_BIT_IICRSV), I2C_REG_IICF0); spin_lock(&i2c_lock); outw((I2C_BIT_IICE0 | I2C_BIT_WTIM0), I2C_REG_IICC0); spin_unlock(&i2c_lock);#ifdef I2C_DEBUG printk(KERN_INFO "mp200_init(): con: %04x, stat: %04x\n", inw(I2C_REG_IICC0), inw(I2C_REG_IICSE0));#endif}/* * Waiting on Bus Busy */static int mp200_i2c_wait_for_bb(struct i2c_adapter *adap){ int timeout = adap->timeout; while ((inw(I2C_REG_IICF0) & I2C_BIT_IICBSY) && timeout--) { /* If irq is setup properly, wait for interrupt. */ schedule_timeout(1); } if (timeout <= 0) { printk(KERN_INFO "mp200_i2c_wait_for_bb(): Timeout, I2C bus is busy\n"); } return (timeout <= 0);}/* * After we issue a transaction on the mp200 I2C bus, this function * is called. It puts this process to sleep until we get an interrupt from * the controller telling us that the transaction we requested is complete. * pin = Pending Interrupt Not */static int mp200_i2c_wait_for_pin(struct i2c_adapter *adap, u16 * status){ int retries = adap->retries; int timeout; int pending = 0; DECLARE_WAITQUEUE(wait, current); if (irq) { add_wait_queue(&i2c_wait, &wait); } do { /* Put the process to sleep. This process will be awakened * when either the the I2C peripheral interrupts or the * timeout expires. */ if (irq) { timeout = adap->timeout; current->state = TASK_INTERRUPTIBLE; spin_lock_irq(&i2c_irq_lock); pending = i2c_pending; i2c_pending = 0; spin_unlock_irq(&i2c_irq_lock); *status = inw(I2C_REG_IICSE0);#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_wait_for_pin(): con: %04x, stat: %04x\n", inw(I2C_REG_IICC0), *status);#endif if (pending) { break; } schedule_timeout(timeout); } else { timeout = adap->timeout * 10000; do { udelay(100000 / clock); if (MP200_I2C_INTC_MST_35 & inw(MP200_I2C_INTC_IT0_RAW1)) { outw(MP200_I2C_INTC_MST_35, MP200_I2C_INTC_IT0_IIR1); pending = 1; break; } } while (--timeout); *status = inw(I2C_REG_IICSE0);#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_wait_for_pin(): con: %04x, stat: %04x\n", inw(I2C_REG_IICC0), *status);#endif if (pending) { break; } } } while ((*status & I2C_BIT_MSTS0) && retries--); if (irq) { current->state = TASK_RUNNING; remove_wait_queue(&i2c_wait, &wait); } if (retries <= 0) { printk(KERN_INFO "mp200_i2c_wait_for_pin(): Timeout\n"); } return (retries <= 0) ? -1 : 0;}/* * Sanity check for the adapter hardware - check the reaction of * the bus lines only if it seems to be idle. * * Scan the I2C bus for valid 7 bit addresses * (ie things that ACK on 1byte read) * if i2c_debug is off we print everything on one line. * if i2c_debug is on we do a newline per print so we don't * clash too much with printf's in the other functions. * TODO: check for 10-bit mode and never run as a slave. */static int mp200_i2c_scan_bus(struct i2c_adapter *adap){ int found = 0; int i; struct i2c_msg msg; char data[1]; printk(KERN_INFO "mp200_i2c_scan_bus(): " "%s: scanning for active I2C devices on the bus.", adap->name); for (i = 1; i < 0x7f; i++) { if ((inw(I2C_REG_SVA0) >> 9) == i) { continue; } msg.addr = i; msg.buf = data; msg.len = 0; msg.flags = I2C_M_RD; if (mp200_i2c_xfer(adap, &msg, 1) == 0) { printk(" 0x%02x", i); found++; } } if (found) { printk("\n"); } else { printk(" Found nothing.\n"); } return found;}/* * Prepare controller for a transaction and call mp200_i2c_rxbytes * to do the work. */static intmp200_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num){ int i; int status = 0;#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_xfer(): msgs: %d\n", num);#endif if ((num < 1) || (num > MAX_MESSAGES)) { return (status = -EINVAL); } /* Check for valid parameters in messages */ for (i = 0; i < num; i++) { if (&msgs[i] == NULL) { return (status = -EINVAL); } if (msgs[i].buf == NULL) { return (status = -EINVAL); } } if ((status = mp200_i2c_wait_for_bb(adap))) { printk(KERN_INFO "mp200_i2c_xfer(): %s: Timeout waiting for busy bus.\n", adap->name); if (!(inw(I2C_REG_IICSE0) & I2C_BIT_MSTS0)) { /* We're not the master but the bus is busy. */ return (status = -EBUSY); } /* This shouldn't happen but we're already the master. * So try to park the bus before starting transaction. */ printk(KERN_INFO "mp200_i2c_xfer(): %s is already active. " "Attempting to Reset module...\n", adap->name); /* stop condition trigger */ spin_lock(&i2c_lock); outw((inw(I2C_REG_IICC0) | I2C_BIT_SPT0), I2C_REG_IICC0); spin_unlock(&i2c_lock); if ((status = mp200_i2c_wait_for_bb(adap))) { /* Eew, still busy, try resetting to unwedge... */ mp200_init(adap); if (mp200_i2c_wait_for_bb(adap)) { printk(KERN_INFO "mp200_i2c_xfer(): " "%s reset failed - I2C bus is wedged.\n", adap->name); /* Just give up... */ return (status = -EREMOTEIO); } } } for (i = 0; i < num; i++) {#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_xfer(): msg: %d, addr: 0x%04x, len: %d, " "flags: 0x%x\n", i, msgs[i].addr, msgs[i].len, msgs[i].flags);#endif status = mp200_i2c_rxbytes(adap, &msgs[i], (i == (num - 1)));#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_xfer(): status loop: %d\n", status);#endif if (status != msgs[i].len) { break; } } /* REVISIT: This is silly but fixup status to return expected results */ if ((status >= 0) && (num > 1)) { status = num; }#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_xfer(): status: %d\n", status);#endif return status;}/* * Low level master read/write transaction. */static intmp200_i2c_rxbytes(struct i2c_adapter *adap, struct i2c_msg *msg, int stop){ u16 status; u8 data = 0; int count = 0; int recv_len = 0; /* I2C_FUNC_SMBUS_READ_BLOCK_DATA coresponded */ if (msg->flags & I2C_M_RECV_LEN) { recv_len = 1; }#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_rxbytes(): addr: 0x%04x, len: %d, " "flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop);#endif if (irq) { spin_lock_irq(&i2c_irq_lock); i2c_pending = 0; spin_unlock_irq(&i2c_irq_lock); } spin_lock(&i2c_lock); outw((inw(I2C_REG_IICC0) | I2C_BIT_STT0), I2C_REG_IICC0); spin_unlock(&i2c_lock); /* 6us wait */ udelay(MP200_I2C_WAIT);#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_rxbytes(): con: %04x, flg: %04x\n", inw(I2C_REG_IICC0), inw(I2C_REG_IICF0));#endif if ((inw(I2C_REG_IICF0) & I2C_BIT_STCF) || !(inw(I2C_REG_IICSE0) & I2C_BIT_MSTS0)) { return -EBUSY; }#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_rxbytes(): addr: %04x, flags: %04x\n", msg->addr, msg->flags); printk(KERN_INFO "mp200_i2c_rxbytes(): addrdir: %04x\n", (msg->addr << I2C_DIR_SHIFT) | ((msg->flags & I2C_M_RD) ? 1 : 0));#endif outw((msg->addr << I2C_DIR_SHIFT) | ((msg->flags & I2C_M_RD) ? 1 : 0), I2C_REG_IIC0); if (mp200_i2c_wait_for_pin(adap, &status)) { /* Timeout */ mp200_init(adap); return -EREMOTEIO; } if (status & I2C_BIT_ALD0) { i2c_arbls += 1; /* need to reset for clear arbitration detect */ mp200_init(adap); return -EREMOTEIO; } else if (status & (I2C_BIT_EXC0 | I2C_BIT_COI0) || !(status & I2C_BIT_MSTS0)) { /* unsupported slave mode and 10bit address mode */ mp200_init(adap); return -EREMOTEIO; } else if (!(status & I2C_BIT_TRC0)) { if (!(msg->flags & I2C_M_RD)) { printk(KERN_INFO "mp200_i2c_rxbytes(): %s r/w hardware fault.\n", adap->name); mp200_init(adap); return -EREMOTEIO; } if (!(status & I2C_BIT_ACKD0)) { printk(KERN_INFO "mp200_i2c_rxbytes(): %s r/w hardware fault.\n", adap->name); /* stop condition trigger */ spin_lock(&i2c_lock); outw((inw(I2C_REG_IICC0) | I2C_BIT_SPT0), I2C_REG_IICC0); spin_unlock(&i2c_lock); return -EREMOTEIO; } spin_lock(&i2c_lock); outw((inw(I2C_REG_IICC0) & ~I2C_BIT_WTIM0) | I2C_BIT_ACKE0 | I2C_BIT_WREL0, I2C_REG_IICC0); spin_unlock(&i2c_lock); if (mp200_i2c_wait_for_pin(adap, &status)) { /* Timeout */ mp200_init(adap); return -EREMOTEIO; } } do { if (status & I2C_BIT_ALD0) { i2c_arbls += 1; /* need to reset for clear arbitration detect */ mp200_init(adap); return -EREMOTEIO; } else if (status & (I2C_BIT_EXC0 | I2C_BIT_COI0) || !(status & I2C_BIT_MSTS0)) { /* unsupported slave mode and 10bit address mode */ mp200_init(adap); return -EREMOTEIO; } else if (!(status & I2C_BIT_TRC0)) { if (!(msg->flags & I2C_M_RD)) { printk(KERN_INFO "mp200_i2c_rxbytes(): %s r/w hardware fault.\n", adap->name); mp200_init(adap); return -EREMOTEIO; } if (count == msg->len) { break; } /* read data */ data = inw(I2C_REG_IIC0);#ifdef I2C_DEBUG printk(KERN_INFO "mp200_i2c_rxbytes(): read: data: %04x\n", data);#endif if (recv_len) { recv_len = 0; /* [Count] should be between 1 and 31 (I2C_SMBUS_BLOCK_MAX - 1). */ if (0 < data && data < I2C_SMBUS_BLOCK_MAX) { /* plus one for [Count] itself */ msg->len = data + 1; } else { printk(KERN_INFO "mp200_i2c_rxbytes(): " "%s : bad block count (%d).\n", adap->name, data); msg->len = 1; recv_len = -1; } } if (count < msg->len) { msg->buf[count++] = data; } else if (msg->len != 0) { /* Er, h/w and/or s/w error? */ printk(KERN_INFO "mp200_i2c_rxbytes(): %s rcv count mismatch.\n", adap->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -