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

📄 twl4030_core.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			local_irq_disable();			if (retval != IRQ_HANDLED)				printk(KERN_ERR "ISR for TWL4030 module"					" irq %d can't handle interrupt\n", irq);			/*			 * Here is where we should call the unmask method, but			 * again we won't bother since it is NULL.			 */		} else			printk(KERN_CRIT "TWL4030 module irq %d has no ISR"					" but can't be masked!\n", irq);	} else		printk(KERN_CRIT "TWL4030 module irq %d is disabled but can't"				" be masked!\n", irq);}/* * twl4030_irq_thread() runs as a kernel thread.  It queries the twl4030 * interrupt controller to see which modules are generating interrupt requests * and then calls the desc->handle method for each module requesting service. */static int twl4030_irq_thread(void *data){	int irq = (int)data;	irq_desc_t *desc = irq_desc + irq;	static unsigned i2c_errors;	const static unsigned max_i2c_errors = 100;	daemonize("twl4030-irq");	current->flags |= PF_NOFREEZE;	while (!kthread_should_stop()) {		int ret;		int module_irq;		u8 pih_isr;		wait_for_completion_interruptible(&irq_event);		ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,					  REG_PIH_ISR_P1);		if (ret) {			printk(KERN_WARNING "I2C error %d while reading TWL4030"					" PIH ISR register.\n", ret);			if (++i2c_errors >= max_i2c_errors) {				printk(KERN_ERR "Maximum I2C error count"						" exceeded.  Terminating %s.\n",						__FUNCTION__);				break;			}			continue;		}		for (module_irq = IH_TWL4030_BASE; 0 != pih_isr;			 pih_isr >>= 1, module_irq++) {			if (pih_isr & 0x1) {				irq_desc_t *d = irq_desc + module_irq;				local_irq_disable();				d->handle_irq(module_irq, d);				local_irq_enable();			}		}		desc->chip->unmask(irq);	}	return 0;}/* * do_twl4030_irq() is the desc->handle method for the twl4030 interrupt. * This is a chained interrupt, so there is no desc->action method for it. * Now we need to query the interrupt controller in the twl4030 to determine * which module is generating the interrupt request.  However, we can't do i2c * transactions in interrupt context, so we must defer that work to a kernel * thread.  All we do here is acknowledge and mask the interrupt and wakeup * the kernel thread. */static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc){	const unsigned int cpu = smp_processor_id();	/*	 * Earlier this was desc->triggered = 1;	 */	desc->status |= IRQ_LEVEL;	/*	 * Acknowledge, clear _AND_ disable the interrupt.	 */	desc->chip->ack(irq);	if (!desc->depth) {		kstat_cpu(cpu).irqs[irq]++;		complete(&irq_event);	}}/* attach a client to the adapter */static int twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid){	int err = 0;	struct twl4030_client *client;	if (unlikely(sid >= TWL4030_NUM_SLAVES)) {		pr_err("sid[%d] > MOD_LAST[%d]\n", sid, TWL4030_NUM_SLAVES);		return -EPERM;	}	/* Check basic functionality */	if (!(err = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |						I2C_FUNC_SMBUS_WRITE_BYTE))) {		pr_err("SlaveID=%d functionality check failed\n", sid);		return err;	}	client = &(twl4030_modules[sid]);	if (unlikely(client->inuse)) {		pr_err("Client %s is already in use\n", client->client_name);		return -EPERM;	}	memset(&(client->client), 0, sizeof(struct i2c_client));	client->client.addr	= client->address;	client->client.adapter	= adapter;	client->client.driver	= &twl4030_driver;	memcpy(&(client->client.name), client->client_name,			sizeof(TWL_CLIENT_STRING) + 1);	pr_info("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n",				client->client_name, adapter->name, err);	if ((err = i2c_attach_client(&(client->client)))) {		pr_err("Couldn't attach Slave %s on Adapter"		       "%s [%x]\n", client->client_name, adapter->name, err);	} else {		client->inuse = TWL_CLIENT_USED;		init_MUTEX(&client->xfer_lock);	}	return err;}/* adapter callback */static int twl4030_attach_adapter(struct i2c_adapter *adapter){	int i;	int ret = 0;	static int twl_i2c_adapter = 1;	for (i = 0; i < TWL4030_NUM_SLAVES; i++) {		/* Check if I need to hook on to this adapter or not */		if (twl4030_modules[i].adapter_index == twl_i2c_adapter) {			if ((ret = twl4030_detect_client(adapter, i)))				goto free_client;		}	}	twl_i2c_adapter++;	/*	 * Check if the PIH module is initialized, if yes, then init	 * the T2 Interrupt subsystem	 */	if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse ==		TWL_CLIENT_USED) && (twl_irq_used != USED)) {		twl_init_irq();		twl_irq_used = USED;	}	twl4030_sysfs_debug_create();	return 0;free_client:	pr_err("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n",i,ret);	/* ignore current slave..it never got registered */	i--;	while (i >= 0) {		/* now remove all those from the current adapter... */		if (twl4030_modules[i].adapter_index == twl_i2c_adapter)			(void)twl4030_detach_client(&(twl4030_modules[i].client));		i--;	}	return ret;}/* adapter's callback */static int twl4030_detach_client(struct i2c_client *iclient){	int err;	twl4030_sysfs_debug_remove();	if ((err = i2c_detach_client(iclient))) {		pr_err("Client detach failed\n");		return err;	}	return 0;}struct task_struct *start_twl4030_irq_thread(int irq){	struct task_struct *thread;	init_completion(&irq_event);	thread = kthread_run(twl4030_irq_thread, (void *)irq,			     "twl4030 irq %d", irq);	if (!thread)		pr_err("%s: could not create twl4030 irq %d thread!\n",		       __FUNCTION__,irq);	return thread;}static void twl_init_irq(void){	int i = 0;	int res = 0;	int line = 0;	/*	 * We end up with interrupts from other modules before	 * they get a chance to handle them...	 */	/* PWR_ISR1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* PWR_ISR2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* PWR_IMR1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* PWR_IMR2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* Clear off any other pending interrupts on power */	/* PWR_ISR1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* PWR_ISR2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* POWER HACK (END) */	/* Slave address 0x4A */	/* BCIIMR1_1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* BCIIMR1_2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* BCIIMR2_1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* BCIIMR2_2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* MAD C */	/* MADC_IMR1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* MADC_IMR2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* key Pad */	/* KEYPAD - IMR1 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x12));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	{		u8 clear;		/* Clear ISR */		twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);		twl4030_i2c_read_u8(TWL4030_MODULE_KEYPAD, &clear, 0x11);	}	/* KEYPAD - IMR2 */	res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x14));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* Slave address 0x49 */	/* GPIO_IMR1A */	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1C));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* GPIO_IMR2A */	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1D));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* GPIO_IMR3A */	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1E));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* GPIO_IMR1B */	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x22));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* GPIO_IMR2B */	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x23));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* GPIO_IMR3B */	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x24));	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}	/* install an irq handler for each of the PIH modules */	for (i = IH_TWL4030_BASE; i < IH_TWL4030_END; i++) {		set_irq_chip(i, &twl4030_irq_chip);		set_irq_handler(i, do_twl4030_module_irq);		set_irq_flags(i, IRQF_VALID);	}	/* install an irq handler to demultiplex the TWL4030 interrupt */	set_irq_data(TWL4030_IRQNUM, start_twl4030_irq_thread(TWL4030_IRQNUM));	set_irq_type(TWL4030_IRQNUM, IRQT_FALLING);	set_irq_chained_handler(TWL4030_IRQNUM, do_twl4030_irq);	res = power_companion_init();	if (res < 0) {		line = __LINE__;		goto irq_exit_path;	}irq_exit_path:	if (res)		pr_err("Unable to register interrupt subsystem[%d][%d]\n",		       res,line);}static int __init twl4030_init(void){	int res;	if ((res = i2c_add_driver(&twl4030_driver))) {		printk(KERN_ERR "TWL4030: Driver registration failed \n");		return res;	}	pr_info(KERN_INFO "TWL4030: Driver registration complete.\n");	return 0;}static void __exit twl4030_exit(void){	i2c_del_driver(&twl4030_driver);	twl_irq_used = FREE;}subsys_initcall(twl4030_init);module_exit(twl4030_exit);EXPORT_SYMBOL(twl4030_i2c_write_u8);EXPORT_SYMBOL(twl4030_i2c_read_u8);EXPORT_SYMBOL(twl4030_i2c_read);EXPORT_SYMBOL(twl4030_i2c_write);MODULE_AUTHOR("Texas Instruments, Inc.");MODULE_DESCRIPTION("I2C Core interface for TWL4030");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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