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

📄 hx4700_power.c

📁 pocket pc hx4700 linux driver
💻 C
📖 第 1 页 / 共 2 页
字号:
{    return 0;}int get_min_current(struct battery *b){    return -1900; /* negative 1900 mA */}int get_min_charge(struct battery *b){    return 0;}int get_max_voltage(struct battery *b){    return 4750; /* mV */}int get_max_current(struct battery *b){    return 1900; /* positive 1900 mA */}int get_max_charge(struct battery *b){    return 1;}int get_temp(struct battery *b){    update_data(0);    return module_data.temp;}int get_voltage(struct battery *b){    update_data(0);    return module_data.voltage;}int get_Current(struct battery *b){    update_data(0);    return module_data.Current;}int get_charge(struct battery *b){    return module_data.current_accum / 4;}int get_status(struct battery *b){    return power_status == POWER_NONE? 0: 1;}static struct battery hx4700_power = {    .name               = "hx4700_primary",    .id                 = "main",    .get_min_voltage    = get_min_voltage,    .get_min_current    = get_min_current,    .get_min_charge     = get_min_charge,    .get_max_voltage    = get_max_voltage,    .get_max_current    = get_max_current,    .get_max_charge     = get_max_charge,    .get_temp           = get_temp,    .get_voltage        = get_voltage,    .get_current        = get_Current,    .get_charge         = get_charge,    .get_status         = get_status,};static voidset_leds(int status, int Current, int battery_life){    if (status == APM_AC_ONLINE) {        /* check life to update LEDs. LEDs are off when on battery */        /*         * It has been observed that the Current is greater when the device is         * suspended compared to when it is awake.  So we have to use         * different parameters here compared to bootldr         */        if((Current < 32) && (battery_life == 100)) {            /* Green LED on solid, amber off */            hx4700_set_led(0, 0, 16);            hx4700_set_led(1, 16, 16);        } else {            /* Amber LED blinking, green off */            hx4700_set_led(0, 128, 256);            hx4700_set_led(1, 0, 16);        }    } else {        /* No charging power is applied; both LEDs off */        hx4700_set_led(0, 0, 16);        hx4700_set_led(1, 0, 16);    }}static voidhx4700_apm_get_power_status( struct apm_power_info *info ){    update_data(0);    info->ac_line_status = (power_status == POWER_NONE)        ? APM_AC_OFFLINE : APM_AC_ONLINE;    /* It is possible to be hooked up to USB and getting some power from     * it, but still having a current drain on the battery with a busy CPU     */    info->battery_life   = module_data.battery_life;    if (info->ac_line_status == APM_AC_ONLINE) {        info->battery_status = APM_BATTERY_STATUS_CHARGING;    } else {        info->time           = module_data.minutes;        info->units          = APM_UNITS_MINS;        module_data.acr_reset = 0;        info->battery_status = APM_BATTERY_STATUS_CRITICAL;        if(info->battery_life > 5) {            info->battery_status = APM_BATTERY_STATUS_LOW;        }        if(info->battery_life > 20) {            info->battery_status = APM_BATTERY_STATUS_HIGH;        }    }    set_leds(info->ac_line_status, module_data.Current, module_data.battery_life);}static voidpower_change_task_handler(unsigned long enableirq){    unsigned int retval;    int ac_in, usb_in;    if(!module_data.initialized) return;    retval = ipaq_asic3_read_gpio_status_d( &hx4700_asic3.dev );    ac_in  = (retval & (1<<GPIOD_AC_IN_N)) == 0;    usb_in = (retval & (1<<GPIOD_USBC_DETECT_N)) == 0;    printk( KERN_INFO "hx4700 power_change: ac_in=%d\n", ac_in );    printk( KERN_INFO "hx4700 power_change: usb_in=%d\n", usb_in );    if (usb_in) {        set_irq_type( module_data.usb_irq, IRQT_RISING );    } else {        set_irq_type( module_data.usb_irq, IRQT_FALLING );    }    if (ac_in) {        set_irq_type( module_data.ac_irq, IRQT_RISING );    } else {        set_irq_type( module_data.ac_irq, IRQT_FALLING );    }    if (ac_in) {        /* If we're on AC, it doesn't matter if we're on USB or not, use AC         * only */        SET_HX4700_GPIO_N( CHARGE_EN, 1 );        SET_HX4700_GPIO( USB_CHARGE_RATE, 0 );        power_status = POWER_AC;        set_leds(APM_AC_ONLINE, module_data.Current, module_data.battery_life);    } else if (usb_in) {        /* We're not on AC, but we are on USB, so charge with that */        SET_HX4700_GPIO( USB_CHARGE_RATE, 1 );        SET_HX4700_GPIO_N( CHARGE_EN, 1 );        power_status = POWER_USB;        set_leds(APM_AC_ONLINE, module_data.Current, module_data.battery_life);    } else {        /* We're not on AC or USB, don't charge */        SET_HX4700_GPIO_N( CHARGE_EN, 0 );        SET_HX4700_GPIO( USB_CHARGE_RATE, 0 );        power_status = POWER_NONE;        hx4700_clear_led(0);        hx4700_clear_led(1);        set_leds(APM_AC_OFFLINE, module_data.Current, module_data.battery_life);        module_data.acr_reset = 0;    }    /* update_data(1); */    module_data.jiffies_64 = 0; /* Force a re-read on next try */    if(enableirq) {        enable_irq(module_data.usb_irq);        enable_irq(module_data.ac_irq);    }}static intattach_isr(int irq, void *dev_id, struct pt_regs *regs){if(irq != module_data.usb_irq    && irq != module_data.ac_irq) {    printk("Bad irq: %d, not %d or %d\n", irq, module_data.usb_irq, module_data.ac_irq);}    if(module_data.initialized) {        SET_HX4700_GPIO_N( CHARGE_EN, 0 );        mod_timer(&module_data.irqtimer, jiffies + HZ/10);        disable_irq(module_data.usb_irq);        disable_irq(module_data.ac_irq);    }    return IRQ_HANDLED;}static intbattery_class_uevent(struct class_device *dev, char **envp, int num_envp,    char *buffer, int buffer_size){        return 0;}static voidbattery_class_release(struct class_device *dev){}static voidbattery_class_class_release(struct class *class){}static voidw1_send_net_address(void){    if(net) {        int i;        w1_write_byte(0x55); /* Match Net Address */        for(i = 0; i < sizeof(module_data.net_address)/sizeof(module_data.net_address[0]); i++) {            w1_write_byte(module_data.net_address[i]);        }    } else {        w1_write_byte(0xcc); /* Skip Net Address */    }}static intw1_probe(struct device *dev){    int retval;    module_data.initialized = 0;    module_data.w1_irq      = -1;    module_data.usb_irq     = -1;    module_data.ac_irq      = -1;    module_data.base        = 0;    module_data.jiffies_64  = 0;    module_data.acr_reset   = 0;    init_timer(&module_data.irqtimer);    module_data.irqtimer.function = power_change_task_handler;    module_data.irqtimer.data     = 1;    init_waitqueue_head(&module_data.irqwait);    dev_set_drvdata(dev, &module_data);    module_data.base = ioremap_nocache(0x0c000600, 64);    module_data.battery_class = 0;    if(!module_data.base) {        printk(KERN_NOTICE "%s: Unable to map device\n", driver_name);        return -ENODEV;    }    module_data.w1_irq = asic3_irq_base(&hx4700_asic3.dev) + ASIC3_OWM_IRQ;    retval = request_irq(module_data.w1_irq, w1_isr, SA_INTERRUPT, driver_name, &module_data);    if(retval) {        printk(KERN_NOTICE "%s: Unable to get interrupt %d: %d\n",            driver_name, module_data.w1_irq, retval);        iounmap((void __iomem *)module_data.base);        module_data.base = 0;        module_data.w1_irq = -1;        return -ENODEV;    }    w1_init();    if(w1_detect()) {        unsigned int readval;        int i;        w1_write_byte(0x33);        for(i = 0; i < sizeof(module_data.net_address)/sizeof(module_data.net_address[0]); i++) {            w1_read_byte(&readval);            module_data.net_address[i] = readval & 0xff;        }        if(module_data.net_address[0] != 0x30) {            printk("Looks like wrong net address is "                "%02x %02x %02x %02x %02x %02x %02x %02x\n",                module_data.net_address[0], module_data.net_address[1],                module_data.net_address[2], module_data.net_address[3],                module_data.net_address[4], module_data.net_address[5],                module_data.net_address[6], module_data.net_address[7]                );        }    } else {        printk("Could not detect device for net address\n");        iounmap((void __iomem *)module_data.base);        free_irq(module_data.w1_irq, &module_data);        module_data.base = 0;        module_data.w1_irq = -1;        return -ENODEV;    }    if(w1_detect()) {        unsigned int readval;        if(battery_class_register(&hx4700_power)) {            printk(KERN_ERR "%s: Could not register battery class\n",                driver_name);        } else {            module_data.battery_class = 1;            hx4700_power.class_dev.class->uevent        = battery_class_uevent;            hx4700_power.class_dev.class->release       = battery_class_release;            hx4700_power.class_dev.class->class_release = battery_class_class_release;        }        w1_send_net_address();        w1_write_byte(0x69); /* Read */        w1_write_byte(0x08); /* Special Feature Address */        w1_read_byte(&readval);        if(!(readval & (1 << 7))) {            printk("PS is low. Writing 1.\n");            /* The PS signal is low. The docs say to write a 1 to it to ensure             * proper operation. */            if(w1_detect()) {                w1_send_net_address();                w1_write_byte(0x6c); /* Write */                w1_write_byte(0x08); /* Special Feature Address */                w1_write_byte(readval | (1 << 7)); /* Data */            } else {                printk("No detect when writing PS\n");            }        }    } else {        printk("%s: Device not detected on init\n", driver_name);        return -ENODEV;    }    module_data.usb_irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE        + GPIOD_USBC_DETECT_N;    module_data.ac_irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE        + GPIOD_AC_IN_N;    module_data.initialized = 1;    /* Get first power state */    power_change_task_handler(0);    /* USB IRQ */    if (request_irq( module_data.usb_irq, attach_isr, SA_INTERRUPT,            "Hx4700 USB Detect", NULL ) != 0) {        printk( KERN_ERR "Unable to configure USB detect interrupt.\n" );        module_data.usb_irq = -1;    }    /* AC IRQ */    if (request_irq( module_data.ac_irq, attach_isr, SA_INTERRUPT,            "Hx4700 AC Detect", NULL ) != 0) {        printk( KERN_ERR "Unable to configure AC detect interrupt.\n" );        module_data.ac_irq = -1;    }#ifdef CONFIG_PM    apm_get_power_status = hx4700_apm_get_power_status;#endif    return 0;}static voidw1_deinit(void){    /* Turn off OWM clock.  I hate to touch the others because they might be     * used by other devices like MMC. */    asic3_set_clock_cdex(&hx4700_asic3.dev,        /* CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | */ CLOCK_CDEX_OWM,        /* CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | */ 0);    /* Clear OWM_EN */    asic3_set_extcf_select(&hx4700_asic3.dev,        ASIC3_EXTCF_OWM_EN, 0);    mdelay(1);}static intw1_remove(struct device *dev){    printk("w1_remove\n");#ifdef CONFIG_PM    apm_get_power_status = NULL;#endif    if(module_data.base) {        w1_deinit();    }    if(module_data.battery_class)  {        battery_class_unregister(&hx4700_power);        printk("battery class unregistered\n");    }    if(module_data.base) {        iounmap((void __iomem *)module_data.base);        printk("Base unmapped\n");    }    if(module_data.w1_irq != -1)   {        disable_irq(module_data.w1_irq);        free_irq(module_data.w1_irq, &module_data);        printk("w1 irq freed\n");    }    if (module_data.ac_irq  != -1) {        disable_irq(module_data.ac_irq);        free_irq( module_data.ac_irq, NULL );        printk("ac irq freed\n");    }    if (module_data.usb_irq != -1) {        disable_irq(module_data.usb_irq);        free_irq( module_data.usb_irq, NULL );        printk("usb irq freed\n");    }    while(timer_pending(&module_data.irqtimer)) {        msleep(100);    }    del_timer(&module_data.irqtimer);    return 0;}static intw1_suspend(struct device *dev, pm_message_t state){    // printk("w1_suspend\n");    w1_deinit();    return 0;}static intw1_resume(struct device *dev){    // printk("w1_resume\n");    w1_init();    /* check for changes to power that may have occurred */    power_change_task_handler(0);    /* I think this will work to ensure the interrupt is unmasked. */    disable_irq(module_data.w1_irq);    enable_irq(module_data.w1_irq);    /* Clear OWM_SMB, set OWM_EN */    asic3_set_extcf_select(&hx4700_asic3.dev, ASIC3_EXTCF_OWM_EN, ASIC3_EXTCF_OWM_EN);    return 0;}static struct device_driver w1_driver = {    .name     = "hx4700-power",    .bus      = &platform_bus_type,    .probe    = w1_probe,    .remove   = w1_remove,    .suspend  = w1_suspend,    .resume   = w1_resume};static int __initw1init(void){    printk(KERN_NOTICE "hx4700 Power Management Driver\n");    return driver_register(&w1_driver);}static void __exitw1exit(void){    driver_unregister(&w1_driver);}module_init(w1init);module_exit(w1exit);MODULE_AUTHOR("Aric D. Blumer, SDG Systems, LLC");MODULE_DESCRIPTION("hx4700 Power Management Driver");MODULE_LICENSE("GPL");/* vim600: set expandtab: */

⌨️ 快捷键说明

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