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

📄 via-pmu.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Device driver for the via-pmu on Apple Powermacs. * * The VIA (versatile interface adapter) interfaces to the PMU, * a 6805 microprocessor core whose primary function is to control * battery charging and system power on the PowerBook 3400 and 2400. * The PMU also controls the ADB (Apple Desktop Bus) which connects * to the keyboard and mouse, as well as the non-volatile RAM * and the RTC (real time clock) chip. * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. * Copyright (C) 2001 Benjamin Herrenschmidt *  * todo: - Cleanup synchro between VIA interrupt and GPIO-based PMU *         interrupt. * * */#include <stdarg.h>#include <linux/config.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/miscdevice.h>#include <linux/blkdev.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/adb.h>#include <linux/pmu.h>#include <linux/cuda.h>#include <linux/smp_lock.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/pm.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/sections.h>#include <asm/irq.h>#include <asm/hardirq.h>#include <asm/pmac_feature.h>#include <asm/uaccess.h>#include <asm/mmu_context.h>#include <asm/sections.h>#include <asm/cputable.h>#include <asm/time.h>#ifdef CONFIG_PMAC_BACKLIGHT#include <asm/backlight.h>#endif/* Some compile options */#undef SUSPEND_USES_PMU#define DEBUG_SLEEP#undef HACKED_PCI_SAVE/* Misc minor number allocated for /dev/pmu */#define PMU_MINOR		154/* How many iterations between battery polls */#define BATTERY_POLLING_COUNT	2static volatile unsigned char *via;/* VIA registers - spaced 0x200 bytes apart */#define RS		0x200		/* skip between registers */#define B		0		/* B-side data */#define A		RS		/* A-side data */#define DIRB		(2*RS)		/* B-side direction (1=output) */#define DIRA		(3*RS)		/* A-side direction (1=output) */#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */#define SR		(10*RS)		/* Shift register */#define ACR		(11*RS)		/* Auxiliary control register */#define PCR		(12*RS)		/* Peripheral control register */#define IFR		(13*RS)		/* Interrupt flag register */#define IER		(14*RS)		/* Interrupt enable register */#define ANH		(15*RS)		/* A-side data, no handshake *//* Bits in B data register: both active low */#define TACK		0x08		/* Transfer acknowledge (input) */#define TREQ		0x10		/* Transfer request (output) *//* Bits in ACR */#define SR_CTRL		0x1c		/* Shift register control bits */#define SR_EXT		0x0c		/* Shift on external clock */#define SR_OUT		0x10		/* Shift out if 1 *//* Bits in IFR and IER */#define IER_SET		0x80		/* set bits in IER */#define IER_CLR		0		/* clear bits in IER */#define SR_INT		0x04		/* Shift register full/empty */#define CB2_INT		0x08#define CB1_INT		0x10		/* transition on CB1 input */static volatile enum pmu_state {	idle,	sending,	intack,	reading,	reading_intr,} pmu_state;static struct adb_request *current_req;static struct adb_request *last_req;static struct adb_request *req_awaiting_reply;static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */static unsigned char *reply_ptr;static int data_index;static int data_len;static volatile int adb_int_pending;static struct adb_request bright_req_1, bright_req_2, bright_req_3;static struct device_node *vias;static int pmu_kind = PMU_UNKNOWN;static int pmu_fully_inited = 0;static int pmu_has_adb;static unsigned char *gpio_reg = NULL;static int gpio_irq = -1;static volatile int pmu_suspended = 0;static spinlock_t pmu_lock;static u8 pmu_intr_mask;static int pmu_version;static int drop_interrupts;#ifdef CONFIG_PMAC_PBOOKstatic int option_lid_wakeup = 1;static int sleep_in_progress;static int can_sleep;#endif /* CONFIG_PMAC_PBOOK */static struct proc_dir_entry *proc_pmu_root;static struct proc_dir_entry *proc_pmu_info;static struct proc_dir_entry *proc_pmu_options;#ifdef CONFIG_PMAC_PBOOKint pmu_battery_count;int pmu_cur_battery;unsigned int pmu_power_flags;struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];static int query_batt_timer = BATTERY_POLLING_COUNT;static struct adb_request batt_req;static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];#endif /* CONFIG_PMAC_PBOOK */int __fake_sleep;int asleep;struct notifier_block *sleep_notifier_list;#ifdef CONFIG_ADBstatic int adb_dev_map = 0;static int pmu_adb_flags;static int pmu_probe(void);static int pmu_init(void);static int pmu_send_request(struct adb_request *req, int sync);static int pmu_adb_autopoll(int devs);static int pmu_adb_reset_bus(void);#endif /* CONFIG_ADB */static int init_pmu(void);static int pmu_queue_request(struct adb_request *req);static void pmu_start(void);static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);static void send_byte(int x);static void recv_byte(void);static void pmu_sr_intr(struct pt_regs *regs);static void pmu_done(struct adb_request *req);static void pmu_handle_data(unsigned char *data, int len,			    struct pt_regs *regs);static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);static int proc_get_info(char *page, char **start, off_t off,			  int count, int *eof, void *data);#ifdef CONFIG_PMAC_BACKLIGHTstatic int pmu_set_backlight_level(int level, void* data);static int pmu_set_backlight_enable(int on, int level, void* data);#endif /* CONFIG_PMAC_BACKLIGHT */#ifdef CONFIG_PMAC_PBOOKstatic void pmu_pass_intr(unsigned char *data, int len);static int proc_get_batt(char *page, char **start, off_t off,			int count, int *eof, void *data);#endif /* CONFIG_PMAC_PBOOK */static int proc_read_options(char *page, char **start, off_t off,			int count, int *eof, void *data);static int proc_write_options(struct file *file, const char *buffer,			unsigned long count, void *data);#ifdef CONFIG_ADBstruct adb_driver via_pmu_driver = {	"PMU",	pmu_probe,	pmu_init,	pmu_send_request,	pmu_adb_autopoll,	pmu_poll,	pmu_adb_reset_bus};#endif /* CONFIG_ADB */extern void low_sleep_handler(void);extern void pmac_sleep_save_intrs(int);extern void pmac_sleep_restore_intrs(void);extern void openpic_sleep_save_intrs(void);extern void openpic_sleep_restore_intrs(void);extern void enable_kernel_altivec(void);extern void enable_kernel_fp(void);#ifdef DEBUG_SLEEPint pmu_polled_request(struct adb_request *req);int pmu_wink(struct adb_request *req);#endif#if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM)static int generic_notify_sleep(struct pmu_sleep_notifier *self, int when);static struct pmu_sleep_notifier generic_sleep_notifier = {	generic_notify_sleep,	SLEEP_LEVEL_MISC,};#endif /* defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM) *//* * This table indicates for each PMU opcode: * - the number of data bytes to be sent with the command, or -1 *   if a length byte should be sent, * - the number of response bytes which the PMU will return, or *   -1 if it will send a length byte. */static const s8 pmu_data_len[256][2] __openfirmwaredata = {/*	   0	   1	   2	   3	   4	   5	   6	   7  *//*00*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*08*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*10*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*18*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},/*20*/	{-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},/*28*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},/*30*/	{ 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*38*/	{ 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},/*40*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*48*/	{ 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},/*50*/	{ 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},/*58*/	{ 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},/*60*/	{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*68*/	{ 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},/*70*/	{ 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*78*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},/*80*/	{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*88*/	{ 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*90*/	{ 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*98*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*a0*/	{ 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},/*a8*/	{ 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*b0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*b8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*c0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*c8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*d0*/	{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*d8*/	{ 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},/*e0*/	{-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},/*e8*/	{ 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},/*f0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*f8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},};static char *pbook_type[] = {	"Unknown PowerBook",	"PowerBook 2400/3400/3500(G3)",	"PowerBook G3 Series",	"1999 PowerBook G3",	"Core99"};#ifdef CONFIG_PMAC_BACKLIGHTstatic struct backlight_controller pmu_backlight_controller = {	pmu_set_backlight_enable,	pmu_set_backlight_level};#endif /* CONFIG_PMAC_BACKLIGHT */int __openfirmwarefind_via_pmu(){	if (via != 0)		return 1;	vias = find_devices("via-pmu");	if (vias == 0)		return 0;	if (vias->next != 0)		printk(KERN_WARNING "Warning: only using 1st via-pmu\n");	if (vias->n_addrs < 1 || vias->n_intrs < 1) {		printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",		       vias->n_addrs, vias->n_intrs);		if (vias->n_addrs < 1 || vias->n_intrs < 1)			return 0;	}	spin_lock_init(&pmu_lock);	pmu_has_adb = 1;	pmu_intr_mask =	PMU_INT_PCEJECT |			PMU_INT_SNDBRT |			PMU_INT_ADB |			PMU_INT_TICK;		if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)	    || device_is_compatible(vias->parent, "ohare")))		pmu_kind = PMU_OHARE_BASED;	else if (device_is_compatible(vias->parent, "paddington"))		pmu_kind = PMU_PADDINGTON_BASED;	else if (device_is_compatible(vias->parent, "heathrow"))		pmu_kind = PMU_HEATHROW_BASED;	else if (device_is_compatible(vias->parent, "Keylargo")) {		struct device_node *gpio, *gpiop;		pmu_kind = PMU_KEYLARGO_BASED;		pmu_has_adb = (find_type_devices("adb") != NULL);		pmu_intr_mask =	PMU_INT_PCEJECT |				PMU_INT_SNDBRT |				PMU_INT_ADB |				PMU_INT_TICK |				PMU_INT_ENVIRONMENT;				gpiop = find_devices("gpio");		if (gpiop && gpiop->n_addrs) {			gpio_reg = ioremap(gpiop->addrs->address, 0x10);			gpio = find_devices("extint-gpio1");			if (gpio && gpio->parent == gpiop && gpio->n_intrs)				gpio_irq = gpio->intrs[0].line;		}	} else		pmu_kind = PMU_UNKNOWN;#ifdef CONFIG_PMAC_PBOOK	if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)		can_sleep = 1;#endif /* CONFIG_PMAC_PBOOK */	via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */	out_8(&via[IFR], 0x7f);			/* clear IFR */	pmu_state = idle;	if (!init_pmu()) {		via = NULL;		return 0;	}	printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",	       PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);	       	sys_ctrler = SYS_CTRLER_PMU;	#if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM)	pmu_register_sleep_notifier(&generic_sleep_notifier);	pm_active = 1;#endif		return 1;}#ifdef CONFIG_ADBstatic int __openfirmwarepmu_probe(){	return vias == NULL? -ENODEV: 0;}static int __openfirmwarepmu_init(void){	if (vias == NULL)		return -ENODEV;	return 0;}#endif /* CONFIG_ADB *//* * We can't wait until pmu_init gets called, that happens too late. * It happens after IDE and SCSI initialization, which can take a few * seconds, and by that time the PMU could have given up on us and * turned us off. * This is called from arch/ppc/kernel/pmac_setup.c:pmac_init2(). */int via_pmu_start(void){	if (vias == NULL)		return -ENODEV;	request_OF_resource(vias, 0, NULL);	bright_req_1.complete = 1;	bright_req_2.complete = 1;	bright_req_3.complete = 1;#ifdef CONFIG_PMAC_PBOOK	batt_req.complete = 1;#endif	if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",			(void *)0)) {		printk(KERN_ERR "VIA-PMU: can't get irq %d\n",		       vias->intrs[0].line);		return -EAGAIN;	}	if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {		if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0))			printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);	}	/* Enable interrupts */	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);	pmu_fully_inited = 1;#ifdef CONFIG_PMAC_BACKLIGHT	/* Enable backlight */	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");#endif /* CONFIG_PMAC_BACKLIGHT */#ifdef CONFIG_PMAC_PBOOK  	if (machine_is_compatible("AAPL,3400/2400") ||  		machine_is_compatible("AAPL,3500"))		pmu_battery_count = 1;	else if (machine_is_compatible("AAPL,PowerBook1998") ||		machine_is_compatible("PowerBook1,1"))		pmu_battery_count = 2;	else {		struct device_node* prim = find_devices("power-mgt");		u32 *prim_info = NULL;		if (prim)			prim_info = (u32 *)get_property(prim, "prim-info", NULL);		if (prim_info) {			/* Other stuffs here yet unknown */			pmu_battery_count = (prim_info[6] >> 16) & 0xff;		}	}#endif /* CONFIG_PMAC_PBOOK */	/* Create /proc/pmu */	proc_pmu_root = proc_mkdir("pmu", 0);	if (proc_pmu_root) {		int i;		proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,					proc_get_info, NULL);#ifdef CONFIG_PMAC_PBOOK		for (i=0; i<pmu_battery_count; i++) {			char title[16];			sprintf(title, "battery_%d", i);			proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,						proc_get_batt, (void *)i);		}#endif /* CONFIG_PMAC_PBOOK */		proc_pmu_options = create_proc_entry("options", 0600, proc_pmu_root);		if (proc_pmu_options) {			proc_pmu_options->nlink = 1;			proc_pmu_options->read_proc = proc_read_options;			proc_pmu_options->write_proc = proc_write_options;		}	}	/* Make sure PMU settle down before continuing. This is _very_ important	 * since the IDE probe may shut interrupts down for quite a bit of time. If	 * a PMU communication is pending while this happens, the PMU may timeout	 * Not that on Core99 machines, the PMU keeps sending us environement	 * messages, we should find a way to either fix IDE or make it call	 * pmu_suspend() before masking interrupts. This can also happens while	 * scolling with some fbdevs.	 */	do {		pmu_poll();	} while (pmu_state != idle);	return 0;}static int __openfirmwareinit_pmu(){	int timeout;	struct adb_request req;	out_8(&via[B], via[B] | TREQ);			/* negate TREQ */	out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK);	/* TACK in, TREQ out */	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);	timeout =  100000;	while (!req.complete) {		if (--timeout < 0) {			printk(KERN_ERR "init_pmu: no response from PMU\n");			return 0;		}		udelay(10);		pmu_poll();	}	/* ack all pending interrupts */	timeout = 100000;	interrupt_data[0] = 1;	while (interrupt_data[0] || pmu_state != idle) {

⌨️ 快捷键说明

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