⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c-mp200.c

📁 The attached file is the driver of I2C
💻 C
📖 第 1 页 / 共 2 页
字号:
				break;			}			if (count < msg->len) {				spin_lock(&i2c_lock);				outw((inw(I2C_REG_IICC0) | I2C_BIT_WREL0),				     I2C_REG_IICC0);				spin_unlock(&i2c_lock);			} else {				spin_lock(&i2c_lock);				outw((inw(I2C_REG_IICC0) & ~I2C_BIT_ACKE0)				     | I2C_BIT_WTIM0 | I2C_BIT_WREL0,				     I2C_REG_IICC0);				spin_unlock(&i2c_lock);			}		} 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;			}			if (count < msg->len) {				data = msg->buf[count++];			} else if (count == msg->len) {				break;			} else if (msg->len != 0) {				/* Er, h/w and/or s/w error? */				printk(KERN_INFO				       "mp200_i2c_rxbytes(): %s xmt count mismatch.\n",				       adap->name);				break;			}#ifdef I2C_DEBUG			printk(KERN_INFO			       "mp200_i2c_rxbytes(): write: data: %04x\n",			       data);#endif			/* write data */			outw(data, I2C_REG_IIC0);		} else {#ifdef I2C_DEBUG			printk(KERN_INFO			       "mp200_i2c_rxbytes(): con: %04x, stat: %04x\n",			       inw(I2C_REG_IICC0), inw(I2C_REG_IICSE0));#endif		}		if (mp200_i2c_wait_for_pin(adap, &status)) {			/* Timeout */			mp200_init(adap);			return -EREMOTEIO;		}	} while (count <= msg->len);#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_rxbytes(): count: %d, len: %d, stop %d\n",	       count, msg->len, stop);#endif	/* Create stop condition */	if (count >= msg->len && stop) {		/* stop condition trigger */		spin_lock(&i2c_lock);		outw((inw(I2C_REG_IICC0) | I2C_BIT_SPT0), I2C_REG_IICC0);		spin_unlock(&i2c_lock);#ifdef I2C_DEBUG		printk(KERN_INFO		       "mp200_i2c_rxbytes(): stop:: con: %04x, stat: %04x\n",		       inw(I2C_REG_IICC0), inw(I2C_REG_IICSE0));#endif	}	if (recv_len) {		return -EINVAL;	}	/* Fixup return status for the silly 0 length probe case */	return (count > 0) ? (msg->len ? count : 0) : count;}/* Simulate a SMBus command using the i2c protocol    No checking of parameters is done!  */static s32mp200_i2c_smbus_xfer_emulated(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. */	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 2];	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];	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, len;	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;	case I2C_SMBUS_BYTE_DATA:		if (read_write == I2C_SMBUS_READ) {			msg[1].len = 1;		} else {			msg[0].len = 2;			msgbuf0[1] = data->byte;		}		break;	case I2C_SMBUS_WORD_DATA:		if (read_write == I2C_SMBUS_READ) {			msg[1].len = 2;		} else {			msg[0].len = 3;			msgbuf0[1] = data->word & 0xff;			msgbuf0[2] = (data->word >> 8) & 0xff;		}		break;	case I2C_SMBUS_PROC_CALL:		num = 2;	/* Special case */		read_write = I2C_SMBUS_READ;		msg[0].len = 3;		msg[1].len = 2;		msgbuf0[1] = data->word & 0xff;		msgbuf0[2] = (data->word >> 8) & 0xff;		break;	case I2C_SMBUS_BLOCK_DATA:		if (read_write == I2C_SMBUS_READ) {			/* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_READ_BLOCK_DATA */			if (!i2c_check_functionality			    (adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {				printk(KERN_INFO				       "mp200_i2c_smbus_xfer_emulated(): "				       "Block read not supported under I2C emulation!\n");				return -1;			}			/* set send message */			msg[0].len = 1;			/* set recv message */			msg[1].flags |= I2C_M_RECV_LEN;			msg[1].len = I2C_SMBUS_BLOCK_MAX + 1;		} else {			msg[0].len = data->block[0] + 2;			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {				printk(KERN_INFO				       "mp200_i2c_smbus_xfer_emulated(): "				       "smbus_access called with invalid block write size (%d)\n",				       data->block[0]);				return -1;			}			for (i = 1; i <= msg[0].len; i++) {				msgbuf0[i] = data->block[i - 1];			}		}		break;	case I2C_SMBUS_I2C_BLOCK_DATA:		if (read_write == I2C_SMBUS_READ) {			msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;		} else {			msg[0].len = data->block[0] + 1;			if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) {				printk(KERN_INFO				       "mp200_i2c_smbus_xfer_emulated(): "				       "i2c_smbus_xfer_emulated called with invalid block "				       "write size (%d)\n", data->block[0]);				return -1;			}			for (i = 1; i <= data->block[0]; i++) {				msgbuf0[i] = data->block[i];			}		}		break;	default:		printk(KERN_INFO "mp200_i2c_smbus_xfer_emulated(): "		       "smbus_access called with invalid size (%d)\n", size);		return -1;	}	/* i2c_transfer() uses I2C_LOCK(adap),	 *  so need to call mp200_i2c_xfer() directly.	 */	if (mp200_i2c_xfer(adapter, msg, num) < 0) {		return -1;	}	if (read_write == I2C_SMBUS_READ) {		switch (size) {		case I2C_SMBUS_BYTE:			data->byte = msgbuf0[0];			break;		case I2C_SMBUS_BYTE_DATA:			data->byte = msgbuf1[0];			break;		case I2C_SMBUS_WORD_DATA:		case I2C_SMBUS_PROC_CALL:			data->word = msgbuf1[0] | (msgbuf1[1] << 8);			break;		case I2C_SMBUS_I2C_BLOCK_DATA:			/* fixed at 32 for now */			data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;			for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) {				data->block[i + 1] = msgbuf1[i];			}			break;		case I2C_SMBUS_BLOCK_DATA:			len = msgbuf1[0] + 1;			for (i = 0; i < len; i++) {				data->block[i] = msgbuf1[i];			}			break;		}	}	return 0;}static intmp200_i2c_control(struct i2c_adapter *adap, unsigned int cmd, unsigned long arg){	i2c_ctrl_t ctrl;	memset(&ctrl, 0, sizeof(ctrl));	switch (cmd) {	case I2C_SET_CTRL:		if (copy_from_user		    (&ctrl, (i2c_ctrl_t *) arg, sizeof(i2c_ctrl_t))) {			return -EFAULT;		}		/* mode */		switch (ctrl.smc) {		case I2C_SMC_NORMAL_SPEED:		case I2C_SMC_HIGH_SPEED:			break;		default:			return -EINVAL;		}		/* digital filter */		switch (ctrl.dfc) {		case I2C_DFC_OFF:			break;		case I2C_DFC_ON:			if (ctrl.smc != I2C_SMC_HIGH_SPEED) {				return -EINVAL;			}			break;		default:			return -EINVAL;		}		/* clock speed */		switch (ctrl.clo) {		case I2C_CLO_1:		case I2C_CLO_2:		case I2C_CLO_3:		case I2C_CLO_4:			break;		default:			return -EINVAL;		}		/* clock extened */		switch (ctrl.clx) {		case I2C_CLX_NORMAL:			break;		case I2C_CLX_HIGH:			/* It is used only high-speed mode			   and cannot select I2C_CLO_4 */			if (ctrl.smc != I2C_SMC_HIGH_SPEED) {				return -EINVAL;			}			if (ctrl.clo == I2C_CLO_4) {				return -EINVAL;			}			break;		default:			return -EINVAL;		}		if (mp200_i2c_wait_for_bb(adap)) {			/* Timeout */			return -EFAULT;		}		*(i2c_ctrl_t *) adap->algo_data = ctrl;		mp200_init(adap);		break;	case I2C_GET_CTRL:		return copy_to_user((void *)arg, adap->algo_data,				    sizeof(i2c_ctrl_t));	default:		return -EINVAL;	};	return 0;}static u32 mp200_i2c_func(struct i2c_adapter *adap){	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |	    I2C_FUNC_SMBUS_READ_BLOCK_DATA;}/* -----exported algorithm data: -------------------------------------	*/static struct i2c_algorithm mp200_i2c_algo = {	.name = "mp200 I2C algorithm",	.id = I2C_ALGO_EXP,	.master_xfer = mp200_i2c_xfer,	.smbus_xfer = mp200_i2c_smbus_xfer_emulated,	.slave_send = NULL,	.slave_recv = NULL,	.algo_control = mp200_i2c_control,	.functionality = mp200_i2c_func,};/*  * registering functions to load algorithms at runtime  */int mp200_i2c_add_bus(struct i2c_adapter *adap){#ifdef I2C_DEBUG	printk(KERN_INFO	       "mp200_i2c_add_bus(): hw routines for %s registered.\n",	       adap->name);#endif	/* register new adapter to i2c module... */	adap->id |= mp200_i2c_algo.id;	adap->algo = &mp200_i2c_algo;	adap->timeout = 100;	adap->retries = 3;	i2c_add_adapter(adap);	mp200_init(adap);	if (i2c_scan) {		if (mp200_i2c_scan_bus(adap) < 0) {			return -ENODEV;		}	}	return 0;}int mp200_i2c_del_bus(struct i2c_adapter *adap){	int res;	if ((res = i2c_del_adapter(adap)) < 0) {		return res;	}#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_del_bus(): adapter unregistered: %s\n",	       adap->name);#endif	return 0;}/* ----- local functions ---------------------------------------------- *//* */static irqreturn_tmp200_i2c_handler(int this_irq, void *dev_id, struct pt_regs *regs){	spin_lock(&i2c_irq_lock);	i2c_pending = 1;	spin_unlock(&i2c_irq_lock);#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_handler(): in interrupt handler\n");#endif	wake_up_interruptible(&i2c_wait);	return IRQ_HANDLED;}/* Lock the region of memory where I/O registers exist.  Request our * interrupt line and register its associated handler. */static int mp200_i2c_hw_resrc_init(void){#ifdef I2C_DEBUG	printk(KERN_INFO "mp200_i2c_hw_resrc_init(): resrc Initializing.\n");#endif	if (irq) {		if (request_irq(irq, mp200_i2c_handler, 0, "mp200_i2c", 0) < 0) {			return -ENODEV;		}	}	return 0;}static void mp200_i2c_release(void){	spin_lock(&i2c_lock);	outw(0, I2C_REG_IICC0);	spin_unlock(&i2c_lock);	if (irq) {		free_irq(irq, 0);	}}/* ------------------------------------------------------------------------ * Encapsulate the above functions in the correct operations structure. * This is only done when more than one hardware adapter is supported. */static i2c_ctrl_t mp200_i2c_ctrl = {	.smc = I2C_SMC_NORMAL_SPEED,	/* mode */	.dfc = I2C_DFC_OFF,	/* digital filter */	.clo = I2C_CLO_1,	/* clock speed */	.clx = I2C_CLX_NORMAL,	/* clock extended */};static struct i2c_adapter mp200_i2c_adap = {	.owner = THIS_MODULE,	.name = "mp200 I2C adapter",	.id = I2C_ALGO_EXP,	/* REVISIT: register for id */	.algo = &mp200_i2c_algo,	.algo_data = &mp200_i2c_ctrl,	.client_register = NULL,	.client_unregister = NULL,};static int mp200_i2c_suspend(struct device *dev, u32 state, u32 level){	switch (level) {	case SUSPEND_DISABLE:		mp200_i2c_wait_for_bb(&mp200_i2c_adap);		break;	default:		break;	}	return 0;}static int mp200_i2c_resume(struct device *dev, u32 level){	switch (level) {	case RESUME_ENABLE:		mp200_init(&mp200_i2c_adap);		break;	default:		break;	}	return 0;}/* Called when the module is loaded.  This function starts the * cascade of calls up through the heirarchy of i2c modules (i.e. up to the *  algorithm layer and into to the core layer) */static int mp200_i2c_probe(struct device *dev){	printk(KERN_INFO "Starting mp200_i2c.\n");	/* Check lower and upper I2C SCL bounds based upon	 * 12MHz I2C module clock source.	 */	if ((clock < 25000) || (clock > 400000)) {		clock = DEFAULT_CLOCK;	}	init_waitqueue_head(&i2c_wait);	if (mp200_i2c_hw_resrc_init() < 0) {		return -ENODEV;	}	if (mp200_i2c_add_bus(&mp200_i2c_adap) < 0) {		return -ENODEV;	}	return 0;}static int mp200_i2c_remove(struct device *dev){	mp200_i2c_del_bus(&mp200_i2c_adap);	mp200_i2c_release();	return 0;}static struct device_driver mp200_i2c_driver = {	.name = "i2c",	.bus = &platform_bus_type,	.probe = mp200_i2c_probe,	.remove = mp200_i2c_remove,	.suspend = mp200_i2c_suspend,	.resume = mp200_i2c_resume,};static int __init mp200_i2c_init(void){	return driver_register(&mp200_i2c_driver);}static void __exit mp200_i2c_exit(void){	driver_unregister(&mp200_i2c_driver);}module_param(clock, int, 0);module_param(irq, int, 0);module_param(i2c_scan, int, 0);MODULE_PARM_DESC(i2c_scan, "Scan for active I2C clients on the bus");MODULE_LICENSE("GPL");module_init(mp200_i2c_init);module_exit(mp200_i2c_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -