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

📄 twl4030_core.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * twl4030_core.c - driver for TWL4030 PM and audio CODEC device * * Copyright (C) 2005-2006 Texas Instruments, Inc. * * Modifications to defer interrupt handling to a kernel thread: * Copyright (C) 2006 MontaVista Software, Inc. * * Based on tlv320aic23.c: * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> * * Code cleanup and modifications to IRQ handler. * by syed khasim <x0khasim@ti.com> * * 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 * */#include <linux/module.h>#include <linux/kernel_stat.h>#include <linux/init.h>#include <linux/time.h>#include <linux/interrupt.h>#include <linux/random.h>#include <linux/syscalls.h>#include <linux/kthread.h>#include <linux/slab_def.h>#include <linux/i2c.h>#include <linux/slab.h>#include <linux/clk.h>#include <linux/device.h>#include <linux/platform_device.h>#include <asm/irq.h>#include <asm/mach/irq.h>#include <asm/arch/twl4030.h>#include <asm/arch/gpio.h>#include <asm/arch/mux.h>#include <asm/arch/power_companion.h>#define DRIVER_NAME			"twl4030"#define pr_err(fmt, arg...)	printk(KERN_ERR DRIVER_NAME ": " fmt, ##arg);/**** Macro Definitions */#define TWL_CLIENT_STRING		"TWL4030-ID"#define TWL_CLIENT_USED			1#define TWL_CLIENT_FREE			0/* IRQ Flags */#define FREE				0#define USED				1/** Primary Interrupt Handler on TWL4030 Registers *//**** Register Definitions */#define REG_PIH_ISR_P1			(0x1)#define REG_PIH_ISR_P2			(0x2)#define REG_PIH_SIR			(0x3)/* Triton Core internal information (BEGIN) *//* Last - for index max*/#define TWL4030_MODULE_LAST		TWL4030_MODULE_SECURED_REG/* Slave address */#define TWL4030_NUM_SLAVES		0x04#define TWL4030_SLAVENUM_NUM0		0x00#define TWL4030_SLAVENUM_NUM1		0x01#define TWL4030_SLAVENUM_NUM2		0x02#define TWL4030_SLAVENUM_NUM3		0x03#define TWL4030_SLAVEID_ID0		0x48#define TWL4030_SLAVEID_ID1		0x49#define TWL4030_SLAVEID_ID2		0x4A#define TWL4030_SLAVEID_ID3		0x4B/* Base Address defns *//* USB ID */#define TWL4030_BASEADD_USB		0x0000/* AUD ID */#define TWL4030_BASEADD_AUDIO_VOICE	0x0000#define TWL4030_BASEADD_GPIO		0x0098#define TWL4030_BASEADD_INTBR		0x0085#define TWL4030_BASEADD_PIH		0x0080#define TWL4030_BASEADD_TEST		0x004C/* AUX ID */#define TWL4030_BASEADD_INTERRUPTS	0x00B9#define TWL4030_BASEADD_LED		0x00EE#define TWL4030_BASEADD_MADC		0x0000#define TWL4030_BASEADD_MAIN_CHARGE	0x0074#define TWL4030_BASEADD_PRECHARGE	0x00AA#define TWL4030_BASEADD_PWM0		0x00F8#define TWL4030_BASEADD_PWM1		0x00FB#define TWL4030_BASEADD_PWMA		0x00EF#define TWL4030_BASEADD_PWMB		0x00F1#define TWL4030_BASEADD_KEYPAD		0x00D2/* POWER ID */#define TWL4030_BASEADD_BACKUP		0x0014#define TWL4030_BASEADD_INT		0x002E#define TWL4030_BASEADD_PM_MASTER	0x0036#define TWL4030_BASEADD_PM_RECIEVER	0x005B#define TWL4030_BASEADD_RTC		0x001C#define TWL4030_BASEADD_SECURED_REG	0x0000/* Triton Core internal information (END) *//* Few power values */#define R_CFG_BOOT			0x05#define R_PROTECT_KEY			0x0E/* access control */#define KEY_UNLOCK1			0xce#define KEY_UNLOCK2			0xec#define KEY_LOCK			0x00#define HFCLK_FREQ_19p2_MHZ		(1 << 0)#define HFCLK_FREQ_26_MHZ		(2 << 0)#define HFCLK_FREQ_38p4_MHZ		(3 << 0)#define HIGH_PERF_SQ			(1 << 3)#define CONFIG_I2C_TWL4030_ID   1   /* on I2C1 for OMAP3 BEAGLE */#define	twl4030_sysfs_debug_create()	/* no definition */#define	twl4030_sysfs_debug_remove()	/* no definition */extern int power_companion_init(void);/**** Helper functions */static inttwl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid);static int twl4030_attach_adapter(struct i2c_adapter *adapter);static int twl4030_detach_client(struct i2c_client *client);static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc);static void twl_init_irq(void);/**** Data Structures *//* To have info on T2 IRQ substem activated or not */static unsigned char twl_irq_used = FREE;static struct completion irq_event;/* Structure to define on TWL4030 Slave ID */struct twl4030_client {	struct i2c_client client;	const char client_name[sizeof(TWL_CLIENT_STRING) + 1];	const unsigned char address;	const char adapter_index;	unsigned char inuse;	/* max numb of i2c_msg required is for read =2 */	struct i2c_msg xfer_msg[2];	/* To lock access to xfer_msg */	struct semaphore xfer_lock;};/* Module Mapping */struct twl4030mapping {	unsigned char sid;	/* Slave ID */	unsigned char base;	/* base address */};/* mapping the module id to slave id and base address */static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {	{ TWL4030_SLAVENUM_NUM0, TWL4030_BASEADD_USB },	{ TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_AUDIO_VOICE },	{ TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_GPIO },	{ TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_INTBR },	{ TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_PIH },	{ TWL4030_SLAVENUM_NUM1, TWL4030_BASEADD_TEST },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_KEYPAD },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MADC },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_INTERRUPTS },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_LED },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_MAIN_CHARGE },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PRECHARGE },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM0 },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWM1 },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMA },	{ TWL4030_SLAVENUM_NUM2, TWL4030_BASEADD_PWMB },	{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_BACKUP },	{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_INT },	{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_MASTER },	{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_RECIEVER },	{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_RTC },	{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_SECURED_REG },};static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES] = {	{		.address	= TWL4030_SLAVEID_ID0,		.client_name	= TWL_CLIENT_STRING "0",		.adapter_index	= CONFIG_I2C_TWL4030_ID,	},	{		.address	= TWL4030_SLAVEID_ID1,		.client_name	= TWL_CLIENT_STRING "1",		.adapter_index	= CONFIG_I2C_TWL4030_ID,	},	{		.address	= TWL4030_SLAVEID_ID2,		.client_name	= TWL_CLIENT_STRING "2",		.adapter_index	= CONFIG_I2C_TWL4030_ID,	},	{		.address	= TWL4030_SLAVEID_ID3,		.client_name	= TWL_CLIENT_STRING "3",		.adapter_index	= CONFIG_I2C_TWL4030_ID,	},};/* One Client Driver , 4 Clients */static struct i2c_driver twl4030_driver = {	.driver.name	= "TWL4030 I2C",	.attach_adapter	= twl4030_attach_adapter,	.detach_client	= twl4030_detach_client,};/* * TWL4030 doesn't have PIH mask, hence dummy function for mask * and unmask. */static void twl4030_i2c_ackirq(unsigned int irq) {}static void twl4030_i2c_disableint(unsigned int irq) {}static void twl4030_i2c_enableint(unsigned int irq) {}/* information for processing in the Work Item */static struct irq_chip twl4030_irq_chip = {	.ack	= twl4030_i2c_ackirq,	.mask	= twl4030_i2c_disableint,	.unmask	= twl4030_i2c_enableint,};/* Global Functions *//* * @brief twl4030_i2c_write - Writes a n bit register in TWL4030 * * @param mod_no - module number * @param *value - an array of num_bytes+1 containing data to write * IMPORTANT - Allocate value num_bytes+1 and valid data starts at *		 Offset 1. * @param reg - register address (just offset will do) * @param num_bytes - number of bytes to transfer * * @return result of operation - 0 is success */int twl4030_i2c_write(u8 mod_no, u8 * value, u8 reg, u8 num_bytes){	int ret;	int sid;	struct twl4030_client *client;	struct i2c_msg *msg;	if (unlikely(mod_no > TWL4030_MODULE_LAST)) {		pr_err("Invalid module Number\n");		return -EPERM;	}	sid = twl4030_map[mod_no].sid;	client = &(twl4030_modules[sid]);	if (unlikely(client->inuse != TWL_CLIENT_USED)) {		pr_err("I2C Client[%d] is not initialized[%d]\n",		       sid,__LINE__);		return -EPERM;	}	down(&(client->xfer_lock));	/*	 * [MSG1]: fill the register address data	 * fill the data Tx buffer	 */	msg = &(client->xfer_msg[0]);	msg->addr = client->address;	msg->len = num_bytes + 1;	msg->flags = 0;	msg->buf = value;	/* over write the first byte of buffer with the register address */	*value = twl4030_map[mod_no].base + reg;	ret = i2c_transfer(client->client.adapter, client->xfer_msg, 1);	up(&(client->xfer_lock));	/* i2cTransfer returns num messages.translate it pls.. */	if (ret >= 0)		ret = 0;	return ret;}/** * @brief twl4030_i2c_read - Reads a n bit register in TWL4030 * * @param mod_no - module number * @param *value - an array of num_bytes containing data to be read * @param reg - register address (just offset will do) * @param num_bytes - number of bytes to transfer * * @return result of operation - num_bytes is success else failure. */int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes){	int ret;	u8 val;	int sid;	struct twl4030_client *client;	struct i2c_msg *msg;	if (unlikely(mod_no > TWL4030_MODULE_LAST)) {		pr_err("Invalid module Number\n");		return -EPERM;	}	sid = twl4030_map[mod_no].sid;	client = &(twl4030_modules[sid]);	if (unlikely(client->inuse != TWL_CLIENT_USED)) {		pr_err("I2C Client[%d] is not initialized[%d]\n", sid,		       __LINE__);		return -EPERM;	}	down(&(client->xfer_lock));	/* [MSG1] fill the register address data */	msg = &(client->xfer_msg[0]);	msg->addr = client->address;	msg->len = 1;	msg->flags = 0;	/* Read the register value */	val = twl4030_map[mod_no].base + reg;	msg->buf = &val;	/* [MSG2] fill the data rx buffer */	msg = &(client->xfer_msg[1]);	msg->addr = client->address;	msg->flags = I2C_M_RD;	/* Read the register value */	msg->len = num_bytes;	/* only n bytes */	msg->buf = value;	ret = i2c_transfer(client->client.adapter, client->xfer_msg, 2);	up(&(client->xfer_lock));	/* i2cTransfer returns num messages.translate it pls.. */	if (ret >= 0)		ret = 0;	return ret;}/** * @brief twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030 * * @param mod_no - module number * @param value - the value to be written 8 bit * @param reg - register address (just offset will do) * * @return result of operation - 0 is success */int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg){	int ret;	/* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */	u8 temp_buffer[2] = { 0 };	/* offset 1 contains the data */	temp_buffer[1] = value;	ret = twl4030_i2c_write(mod_no, temp_buffer, reg, 1);	return ret;}/** * @brief twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030 * * @param mod_no - module number * @param *value - the value read 8 bit * @param reg - register address (just offset will do) * * @return result of operation - 0 is success */int twl4030_i2c_read_u8(u8 mod_no, u8 * value, u8 reg){	int ret = 0;	ret = twl4030_i2c_read(mod_no, value, reg, 1);	return ret;}/**** Helper Functions *//* * do_twl4030_module_irq() is the desc->handle method for each of the twl4030 * module interrupts.  It executes in kernel thread context. * On entry, cpu interrupts are disabled. */static void do_twl4030_module_irq(unsigned int irq, irq_desc_t *desc){	struct irqaction *action;	const unsigned int cpu = smp_processor_id();	/*	 * Earlier this was desc->triggered = 1;	 */	desc->status |= IRQ_LEVEL;	/*	 * The desc->handle method would normally call the desc->chip->ack	 * method here, but we won't bother since our ack method is NULL.	 */	if (!desc->depth) {		kstat_cpu(cpu).irqs[irq]++;		action = desc->action;		if (action) {			int ret;			int status = 0;			int retval = 0;			local_irq_enable();			do {				/* Call the ISR with cpu interrupts enabled */				ret = action->handler(irq, action->dev_id);				if (ret == IRQ_HANDLED)					status |= action->flags;				retval |= ret;				action = action->next;			} while (action);			if (status & IRQF_SAMPLE_RANDOM)				add_interrupt_randomness(irq);

⌨️ 快捷键说明

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