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

📄 hx4700_power.c

📁 pocket pc hx4700 linux driver
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright 2005, SDG Systems, LLC * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive for * more details. * * Sat 11 Jun 2005   Aric D. Blumer */#include <linux/module.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/soc/asic3_base.h>#include <linux/delay.h>#include <linux/battery.h>#include <asm/io.h>#include <asm/apm.h>#include <asm/hardware/ipaq-asic3.h>#include <asm/arch/hx4700-gpio.h>#include <asm/arch/hx4700-asic.h>#include <asm/arch/hx4700-core.h>#define DRIVER_NAME "hx4700_power"static char driver_name[] = DRIVER_NAME;static void w1_init(void);static void w1_deinit(void);static enum {    POWER_NONE,    POWER_AC,    POWER_USB,} power_status;static int cdiv = 0x2;static int net = 0x0;module_param(cdiv, int, 0444);MODULE_PARM_DESC(cdiv, "Clock Divisor");module_param(net, int, 0444);MODULE_PARM_DESC(net, "Use net address");struct w1_data {    volatile unsigned short __iomem *base;    int w1_irq;    wait_queue_head_t irqwait;    unsigned short data_register;    unsigned short irqstatus;    int battery_class;    struct timer_list irqtimer;    unsigned int temp;    unsigned int voltage;    int Current;    int current_accum;    int acr_reset;    int minutes;    int battery_life;    int ac_irq;    int usb_irq;    int initialized;    char net_address[8];    u64 jiffies_64;} module_data;#define DS1WM_COMMAND   0#define DS1WM_TXRX      1#define DS1WM_IRQ       2#define DS1WM_IRQ_EN    3#define DS1WM_CLOCK_DIV 4#define WRITE_REGISTER(r, value) do {                           \        /* printk("Write %p = 0x%04x\n", (module_data.base + (r)), value); */ \        ((*(module_data.base + (r))) = (value));                \    } while(0)#define READ_REGISTER(R, r)  do {                               \        (R = *(module_data.base + (r)));                        \        /* printk("Read %p = 0x%04x\n", (module_data.base + (r)), R); */ \    } while(0)static int w1_detect(void);static int w1_write_byte(unsigned short data);static int w1_read_byte(unsigned int *data);static void w1_send_net_address(void);DECLARE_MUTEX(update_mutex);static voidupdate_data(int force){    int flag = 0;    int retries = 30;    /* Only allow an update every second. */    if(!force && (module_data.jiffies_64 + 5 * HZ > jiffies_64)) {        return;    }    if(down_trylock(&update_mutex)) {        return;    }try_again:    if(w1_detect()) {        unsigned int readval;        w1_send_net_address();        w1_write_byte(0x69); /* Read */        w1_write_byte(0x00); /* Starting at offset 0x0 */        w1_read_byte(&readval);                     /* 0x0 */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops\n");                goto exit_please;            }            goto try_again;        }        /* Get rid of stuff we don't want */        w1_read_byte(&readval);                     /* 0x1 */        w1_read_byte(&readval);                     /* 0x2 */        w1_read_byte(&readval);                     /* 0x3 */        w1_read_byte(&readval);                     /* 0x4 */        w1_read_byte(&readval);                     /* 0x5 */        w1_read_byte(&readval);                     /* 0x6 */        w1_read_byte(&readval);                     /* 0x7 */        w1_read_byte(&readval);                     /* 0x8 */        w1_read_byte(&readval);                     /* 0x9 */        w1_read_byte(&readval);                     /* 0xa */        w1_read_byte(&readval);                     /* 0xb */        /* VOLTAGE */        w1_read_byte(&readval);                     /* 0xc */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        module_data.voltage = readval << 8;        w1_read_byte(&readval);                     /* 0xd */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        module_data.voltage |= readval;        module_data.voltage >>= 5;        /* 4997 / 1024 is almost equal to 4880 / 1000 */        module_data.voltage *= 4997;        module_data.voltage /= 1024;        /****************/        /* Current */        w1_read_byte(&readval);                     /* 0xe */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        if(readval & (1 << 7)) {            /* The sign bit is set */            module_data.Current = -1 ^ 0x7fff;        } else {            module_data.Current = 0;        }        module_data.Current |= readval << 8;        w1_read_byte(&readval);                     /* 0xf */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        module_data.Current |= readval;        module_data.Current >>= 3;        /* 655360 / 1024*1024 is equal to 6250000 / 1000000 */        module_data.Current *= 655360;        module_data.Current /= 1024 * 1024;        /****************/        /* Current Accumulator */        w1_read_byte(&readval);                     /* 0x10 */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        if(readval & (1 << 7)) {            /* The sign bit is set */            module_data.current_accum = -1 ^ 0xffff;        } else {            module_data.current_accum = 0;        }        module_data.current_accum |= readval << 8;        w1_read_byte(&readval);                     /* 0x11 */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        module_data.current_accum |= readval;        /* Units are 250 uAh. We wan't mAh. So each unit is 1/4 mAh.  But            * we want fractions of hours, so let's keep the 1/4 mAh units. */        /* Now convert to quarter hours by dividing by mA. */        if(module_data.Current == 0) {            module_data.minutes = module_data.current_accum * 15;        } else {            module_data.minutes = -((module_data.current_accum * 15) / module_data.Current);        }        /****************/        /* Get rid of stuff we don't want */        w1_read_byte(&readval);                     /* 0x12 */        w1_read_byte(&readval);                     /* 0x13 */        w1_read_byte(&readval);                     /* 0x14 */        w1_read_byte(&readval);                     /* 0x15 */        w1_read_byte(&readval);                     /* 0x16 */        w1_read_byte(&readval);                     /* 0x17 */        /* Temperature */        w1_read_byte(&readval);                     /* 0x18 */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        module_data.temp = readval << 8;        w1_read_byte(&readval);                     /* 0x19 */        if(readval == 0xff) {            /*             * We have an unknown read problem. Try again.             */            msleep(1 * retries);            if(0 == retries--) {                // printk("hx4700_power: Whoops2\n");                goto exit_please;            }            goto try_again;        }        module_data.temp |= readval;        module_data.temp >>= 5;        module_data.temp += module_data.temp / 4;        /****************/        if(module_data.voltage > 8000) {            /* There is an unknown problem where things get into a strange             * state.  We know it because the voltage is reported as too             * high.  This is an attempt at robustness to correct the problem.             * I'd like to fix it permanently, though.             */            if(!flag) {                printk("%s: Bad state detected. Retrying.\n", driver_name);                flag = 1;                mdelay(1);                goto try_again;            } else {                printk("w1 fix didn't work. We give up.\n");            }        }        /* Reset ACR when battery gets full. */        if (module_data.Current >= 0 && module_data.Current < 32 &&            !module_data.acr_reset) {                printk(KERN_INFO "ACR reset\n");                module_data.current_accum = 1800 * 4;                if (w1_detect()) {                        w1_send_net_address();                        w1_write_byte(0x6c); /* write */                        w1_write_byte(0x10); /* current accum msb */                        w1_write_byte((module_data.current_accum >> 8) & 0xff);                        w1_write_byte(module_data.current_accum & 0xff);                        module_data.acr_reset = 1;                }        }        module_data.battery_life   = (module_data.current_accum * 25) / 1800;        if(module_data.battery_life > 100) module_data.battery_life = 100;        if(module_data.battery_life < 0) module_data.battery_life = 0;    } else {        printk("%s: Device not detected\n", driver_name);        module_data.temp          = 0;        module_data.voltage       = 0;        module_data.current_accum = 0;        module_data.Current       = 0;    }exit_please:    module_data.jiffies_64 = jiffies_64;    up(&update_mutex);}static irqreturn_tw1_isr(int irq, void *opaque, struct pt_regs *regs){    /*     * Note that the w1 control logic is quite slow, running at 1 MHz.  It is     * possible to read the IRQ status, and return and the interrupt still be     * active.  In this case, we're OK because we only update the irqstatus     * when an actual interrupt causing bit is set.     */    unsigned short tmp;    /* Just reading the register clears the source */    READ_REGISTER(tmp, DS1WM_IRQ);    if(    tmp & (1 << 0)  /* Presence Detect */        || tmp & (1 << 4)  /* Receive Buffer Full */    ) {        int junk, count;        module_data.irqstatus = tmp;        for(count = 0; count < 10; count++) {            READ_REGISTER(module_data.data_register, DS1WM_TXRX);            READ_REGISTER(junk, DS1WM_CLOCK_DIV); /* Delay */            READ_REGISTER(tmp, DS1WM_IRQ);            if(!(tmp & (1 << 4))) break;        }        wake_up_interruptible(&module_data.irqwait);    }    return IRQ_HANDLED;}static voidw1_init(void){    /* Turn on external clocks and the OWM clock */    asic3_set_clock_cdex(&hx4700_asic3.dev,        CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM,        CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM);    mdelay(1);    asic3_set_extcf_reset(&hx4700_asic3.dev, (1 << 6), (1 << 6));    mdelay(1);    asic3_set_extcf_reset(&hx4700_asic3.dev, (1 << 6), 0);    mdelay(1);    /* Clear OWM_SMB, set OWM_EN */    asic3_set_extcf_select(&hx4700_asic3.dev,        ASIC3_EXTCF_OWM_SMB | ASIC3_EXTCF_OWM_EN,        0                   | ASIC3_EXTCF_OWM_EN);    mdelay(1);    WRITE_REGISTER(DS1WM_CLOCK_DIV, cdiv);    /* Enable interrupts: RBF, PD */    /* Set Interrupt Active High (IAS = 1) */    WRITE_REGISTER(DS1WM_IRQ_EN,          (0 << 6)      /* ENBSY */        | (0 << 5)      /* ESINT */        | (1 << 4)      /* ERBF */        | (0 << 3)      /* ETMT */        | (0 << 2)      /* ETBE */        | (1 << 1)      /* IAS  0 = active low interrupt, 1 = active high */        | (1 << 0)      /* EPD */        );    mdelay(1);    /* Set asic3 interrupt status to zero.  Hmmmmm. not accesible in     * asic3_base.c */}static intw1_detect(void){    int retry_count = 5;try_again:    module_data.irqstatus = 0;    /* Set 1WR (one wire reset) bit */    WRITE_REGISTER(DS1WM_COMMAND, 1);    if(wait_event_interruptible_timeout(module_data.irqwait,                module_data.irqstatus & (1 << 0) /* PD set? */, HZ)) {        if(0 == (module_data.irqstatus & (1 << 1)) /* PDR set? */) {            mdelay(1);            return 1;        }    } else {        printk("%s: detect timeout\n", driver_name);    }    if(retry_count--) {        mdelay(1);        goto try_again;    }    return 0;}static intw1_read_byte(unsigned int *data){    module_data.irqstatus = 0;    WRITE_REGISTER(DS1WM_TXRX, 0xff);    if(wait_event_interruptible_timeout(module_data.irqwait,                module_data.irqstatus & (1 << 4) /* RBF set? */, HZ)) {        *data = module_data.data_register;        return 1;    } else {        printk("%s: RBF not set\n", driver_name);    }    return 0;}static intw1_write_byte(unsigned short data){    module_data.irqstatus = 0;    WRITE_REGISTER(DS1WM_TXRX, data);    if(wait_event_interruptible_timeout(module_data.irqwait,                module_data.irqstatus & (1 << 2) /* TBE set? */, HZ)) {        return 1;    } else {        printk("%s: TBE not set\n", driver_name);    }    return 0;}int get_min_voltage(struct battery *b)

⌨️ 快捷键说明

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