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

📄 i2c-keywest.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	rc = iface->result;		pr_debug("transfer done, result: %d\n", rc);	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)	    	data->word = le16_to_cpu(cur_word);		/* Release sem */	pmac_low_i2c_unlock(iface->node);		return rc;}/* * Generic i2c master transfer entrypoint */static intkeywest_xfer(	struct i2c_adapter *adap,		struct i2c_msg msgs[], 		int num){	struct keywest_chan* chan = i2c_get_adapdata(adap);	struct keywest_iface* iface = chan->iface;	struct i2c_msg *pmsg;	int i, completed;	int rc = 0;	if (iface->state == state_dead)		return -ENXIO;	if (pmac_low_i2c_lock(iface->node))		return -ENXIO;	/* Set adapter to standard mode */	iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;	iface->cur_mode |= KW_I2C_MODE_STANDARD;	completed = 0;	for (i = 0; rc >= 0 && i < num;) {		u8 addr;				pmsg = &msgs[i++];		addr = pmsg->addr;		if (pmsg->flags & I2C_M_TEN) {			printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n");			rc = -EINVAL;			break;		}		pr_debug("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n",		     chan->chan_no,		     pmsg->flags & I2C_M_RD ? "read" : "write",                     pmsg->len, addr, i, num);    		/* Setup channel & clear pending irqs */		write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));		write_reg(reg_isr, read_reg(reg_isr));		write_reg(reg_status, 0);				iface->data = pmsg->buf;		iface->datalen = pmsg->len;		iface->state = state_addr;		iface->result = 0;		if (pmsg->flags & I2C_M_RD)			iface->read_write = I2C_SMBUS_READ;		else			iface->read_write = I2C_SMBUS_WRITE;		/* Set up address and r/w bit */		if (pmsg->flags & I2C_M_REV_DIR_ADDR)			addr ^= 1;				write_reg(reg_addr,			(addr << 1) |			((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));#ifndef POLLED_MODE		/* Arm timeout */		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;		add_timer(&iface->timeout_timer);#endif		/* Start sending address & enable interrupt*/		write_reg(reg_ier, KW_I2C_IRQ_MASK);		write_reg(reg_control, KW_I2C_CTL_XADDR);#ifdef POLLED_MODE		pr_debug("using polled mode...\n");		/* State machine, to turn into an interrupt handler */		while(iface->state != state_idle) {			u8 isr = wait_interrupt(iface);			handle_interrupt(iface, isr);		}#else /* POLLED_MODE */		pr_debug("using interrupt mode...\n");		wait_for_completion(&iface->complete);	#endif /* POLLED_MODE */			rc = iface->result;		if (rc == 0)			completed++;		pr_debug("transfer done, result: %d\n", rc);	}	/* Release sem */	pmac_low_i2c_unlock(iface->node);	return completed;}static u32keywest_func(struct i2c_adapter * adapter){	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |	       I2C_FUNC_SMBUS_BLOCK_DATA;}/* For now, we only handle combined mode (smbus) */static struct i2c_algorithm keywest_algorithm = {	.name		= "Keywest i2c",	.id		= I2C_ALGO_SMBUS,	.smbus_xfer	= keywest_smbus_xfer,	.master_xfer	= keywest_xfer,	.functionality	= keywest_func,};static intcreate_iface(struct device_node *np, struct device *dev){	unsigned long steps;	unsigned bsteps, tsize, i, nchan, addroffset;	struct keywest_iface* iface;	u32 *psteps, *prate;	int rc;	if (pmac_low_i2c_lock(np))		return -ENODEV;	psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);	steps = psteps ? (*psteps) : 0x10;	/* Hrm... maybe we can be smarter here */	for (bsteps = 0; (steps & 0x01) == 0; bsteps++)		steps >>= 1;	if (np->parent->name[0] == 'u') {		nchan = 2;		addroffset = 3;	} else {		addroffset = 0;		nchan = 1;	}	tsize = sizeof(struct keywest_iface) +		(sizeof(struct keywest_chan) + 4) * nchan;	iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL);	if (iface == NULL) {		printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");		pmac_low_i2c_unlock(np);		return -ENOMEM;	}	memset(iface, 0, tsize);	spin_lock_init(&iface->lock);	init_completion(&iface->complete);	iface->node = of_node_get(np);	iface->bsteps = bsteps;	iface->chan_count = nchan;	iface->state = state_idle;	iface->irq = np->intrs[0].line;	iface->channels = (struct keywest_chan *)		(((unsigned long)(iface + 1) + 3UL) & ~3UL);	iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset,						np->addrs[0].size);	if (iface->base == 0) {		printk(KERN_ERR "i2c-keywest: can't map inteface !\n");		kfree(iface);		pmac_low_i2c_unlock(np);		return -ENOMEM;	}#ifndef POLLED_MODE	init_timer(&iface->timeout_timer);	iface->timeout_timer.function = keywest_timeout;	iface->timeout_timer.data = (unsigned long)iface;#endif	/* Select interface rate */	iface->cur_mode = KW_I2C_MODE_100KHZ;	prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);	if (prate) switch(*prate) {	case 100:		iface->cur_mode = KW_I2C_MODE_100KHZ;		break;	case 50:		iface->cur_mode = KW_I2C_MODE_50KHZ;		break;	case 25:		iface->cur_mode = KW_I2C_MODE_25KHZ;		break;	default:		printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n",		       (long)*prate);	}		/* Select standard mode by default */	iface->cur_mode |= KW_I2C_MODE_STANDARD;		/* Write mode */	write_reg(reg_mode, iface->cur_mode);		/* Switch interrupts off & clear them*/	write_reg(reg_ier, 0x00);	write_reg(reg_isr, KW_I2C_IRQ_MASK);#ifndef POLLED_MODE	/* Request chip interrupt */		rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface);	if (rc) {		printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);		iounmap((void *)iface->base);		kfree(iface);		pmac_low_i2c_unlock(np);		return -ENODEV;	}#endif /* POLLED_MODE */	pmac_low_i2c_unlock(np);	dev_set_drvdata(dev, iface);		for (i=0; i<nchan; i++) {		struct keywest_chan* chan = &iface->channels[i];		u8 addr;				sprintf(chan->adapter.name, "%s %d", np->parent->name, i);		chan->iface = iface;		chan->chan_no = i;		chan->adapter.id = I2C_ALGO_SMBUS;		chan->adapter.algo = &keywest_algorithm;		chan->adapter.algo_data = NULL;		chan->adapter.client_register = NULL;		chan->adapter.client_unregister = NULL;		i2c_set_adapdata(&chan->adapter, chan);		chan->adapter.dev.parent = dev;		rc = i2c_add_adapter(&chan->adapter);		if (rc) {			printk("i2c-keywest.c: Adapter %s registration failed\n",				chan->adapter.name);			i2c_set_adapdata(&chan->adapter, NULL);		}		if (probe) {			printk("Probe: ");			for (addr = 0x00; addr <= 0x7f; addr++) {				if (i2c_smbus_xfer(&chan->adapter,addr,				    0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)					printk("%02x ", addr);			}			printk("\n");		}	}	printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",		np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);			return 0;}static intdispose_iface(struct device *dev){	struct keywest_iface *iface = dev_get_drvdata(dev);	int i, rc;		/* Make sure we stop all activity */	if (pmac_low_i2c_lock(iface->node))		return -ENODEV;#ifndef POLLED_MODE	spin_lock_irq(&iface->lock);	while (iface->state != state_idle) {		spin_unlock_irq(&iface->lock);		set_task_state(current,TASK_UNINTERRUPTIBLE);		schedule_timeout(HZ/10);		spin_lock_irq(&iface->lock);	}#endif /* POLLED_MODE */	iface->state = state_dead;#ifndef POLLED_MODE	spin_unlock_irq(&iface->lock);	free_irq(iface->irq, iface);#endif /* POLLED_MODE */	pmac_low_i2c_unlock(iface->node);	/* Release all channels */	for (i=0; i<iface->chan_count; i++) {		struct keywest_chan* chan = &iface->channels[i];		if (i2c_get_adapdata(&chan->adapter) == NULL)			continue;		rc = i2c_del_adapter(&chan->adapter);		i2c_set_adapdata(&chan->adapter, NULL);		/* We aren't that prepared to deal with this... */		if (rc)			printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n");	}	iounmap((void *)iface->base);	dev_set_drvdata(dev, NULL);	of_node_put(iface->node);	kfree(iface);	return 0;}static intcreate_iface_macio(struct macio_dev* dev, const struct of_match *match){	return create_iface(dev->ofdev.node, &dev->ofdev.dev);}static intdispose_iface_macio(struct macio_dev* dev){	return dispose_iface(&dev->ofdev.dev);}static intcreate_iface_of_platform(struct of_device* dev, const struct of_match *match){	return create_iface(dev->node, &dev->dev);}static intdispose_iface_of_platform(struct of_device* dev){	return dispose_iface(&dev->dev);}static struct of_match i2c_keywest_match[] = {	{	.name 		= OF_ANY_MATCH,	.type		= "i2c",	.compatible	= "keywest"	},	{},};static struct macio_driver i2c_keywest_macio_driver = {	.name 		= "i2c-keywest",	.match_table	= i2c_keywest_match,	.probe		= create_iface_macio,	.remove		= dispose_iface_macio};static struct of_platform_driver i2c_keywest_of_platform_driver = {	.name 		= "i2c-keywest",	.match_table	= i2c_keywest_match,	.probe		= create_iface_of_platform,	.remove		= dispose_iface_of_platform};static int __initi2c_keywest_init(void){	of_register_driver(&i2c_keywest_of_platform_driver);	macio_register_driver(&i2c_keywest_macio_driver);	return 0;}static void __exiti2c_keywest_cleanup(void){	of_unregister_driver(&i2c_keywest_of_platform_driver);	macio_unregister_driver(&i2c_keywest_macio_driver);}module_init(i2c_keywest_init);module_exit(i2c_keywest_cleanup);

⌨️ 快捷键说明

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