static int asuspec_irq_ec_request(struct i2c_client *client) { int rc = 0 ; unsigned gpio = asuspec_ecreq_gpio; int irq = gpio_to_irq(gpio); const char* label = "asuspec_request" ; ASUSPEC_INFO("gpio = %d, irq = %d\n", gpio,irq); ASUSPEC_INFO("GPIO = %d , state = %d\n", gpio, gpio_get_value(gpio)); rc = gpio_request(gpio, label); if (rc) { ASUSPEC_ERR("gpio_request failed for input %d\n", gpio); goto err_exit; } rc = gpio_direction_output(gpio, 1) ; if (rc) { ASUSPEC_ERR("gpio_direction_output failed for input %d\n", gpio); goto err_exit; } ASUSPEC_INFO("GPIO = %d , state = %d\n", gpio, gpio_get_value(gpio)); return 0 ; err_exit: return rc; }
static int asuspec_dockram_read_battery(int cmd) { int ret = 0; if (ec_chip->ec_ram_init != ASUSPEC_MAGIC_NUM){ ASUSPEC_ERR("DockRam is not ready.\n"); return -1; } if (ec_chip->op_mode){ ASUSPEC_ERR("It's not allowed to access dockram under FW update mode.\n"); return -2; } ret = i2c_smbus_read_i2c_block_data(&dockram_client, cmd, 32, ec_chip->i2c_dm_battery); if (ret < 0) { ASUSPEC_ERR("Fail to read dockram battery, status %d\n", ret); ret = -1; } else { if (ec_chip->apwake_disabled){ mutex_lock(&ec_chip->irq_lock); if (ec_chip->apwake_disabled){ enable_irq(gpio_to_irq(asuspec_apwake_gpio)); enable_irq_wake(gpio_to_irq(asuspec_apwake_gpio)); ec_chip->apwake_disabled = 0; ASUSPEC_ERR("Enable pad apwake\n"); } mutex_unlock(&ec_chip->irq_lock); } ec_chip->i2c_err_count = 0; } ASUSPEC_I2C_DATA(ec_chip->i2c_dm_battery, dbg_counter); return ret; }
static int asuspec_i2c_read_data(struct i2c_client *client) { int ret = 0; if (ec_chip->op_mode){ ASUSPEC_ERR("It's not allowed to access ec under FW update mode.\n"); return -1; } if (ec_chip->i2c_err_count > ASUSPEC_I2C_ERR_TOLERANCE){ mutex_lock(&ec_chip->irq_lock); if(!ec_chip->apwake_disabled){ disable_irq_nosync(gpio_to_irq(asuspec_apwake_gpio)); disable_irq_wake(gpio_to_irq(asuspec_apwake_gpio)); ec_chip->apwake_disabled = 1; ASUSPEC_ERR("Disable pad apwake\n"); } mutex_unlock(&ec_chip->irq_lock); return -3; } ret = i2c_smbus_read_i2c_block_data(client, 0x6A, 8, ec_chip->i2c_data); if (ret < 0) { ASUSPEC_ERR("Fail to read data, status %d\n", ret); ec_chip->i2c_err_count++; } else { ec_chip->i2c_err_count = 0; } ASUSPEC_I2C_DATA(ec_chip->i2c_data, dbg_counter); return ret; }
static int asuspec_dockram_read_storageinfo(int cmd) { int ret = 0; if (ec_chip->ec_ram_init != ASUSPEC_MAGIC_NUM){ ASUSPEC_ERR("DockRam is not ready.\n"); return -1; } if (ec_chip->op_mode){ ASUSPEC_ERR("It's not allowed to access dockram under FW update mode.\n"); return -2; } if (ec_chip->i2c_err_count > ASUSPEC_I2C_ERR_TOLERANCE){ return -3; } ret = i2c_smbus_read_i2c_block_data(&dockram_client, cmd, 32, ec_chip->i2c_dm_storage); if (ret < 0) { ASUSPEC_ERR("Fail to read dockram data, status %d\n", ret); } else { ec_chip->i2c_err_count = 0; } return ret; }
int asuspec_battery_monitor(char *cmd){ int ret_val = 0; if (ec_chip->ec_in_s3){ asuspec_send_ec_req(); msleep(200); } ret_val = asuspec_dockram_read_battery(0x14); if (ret_val == -1){ ASUSPEC_ERR("Fail to access battery info.\n"); return -1; } else { #if FACTORY_MODE if((factory_mode != 2) && (ec_chip->audio_recording == 0)){ mod_timer(&ec_chip->asuspec_timer,jiffies+(HZ * 1)); } #else if(ec_chip->audio_recording == 0){ mod_timer(&ec_chip->asuspec_timer,jiffies+(HZ * 1)); } #endif if (!strcmp(cmd, "status")) ret_val = (ec_chip->i2c_dm_battery[2] << 8 ) | ec_chip->i2c_dm_battery[1]; else if (!strcmp(cmd, "temperature")) ret_val = (ec_chip->i2c_dm_battery[8] << 8 ) | ec_chip->i2c_dm_battery[7]; else if (!strcmp(cmd, "voltage")) ret_val = (ec_chip->i2c_dm_battery[10] << 8 ) | ec_chip->i2c_dm_battery[9]; else if (!strcmp(cmd, "current")) ret_val = (ec_chip->i2c_dm_battery[12] << 8 ) | ec_chip->i2c_dm_battery[11]; else if (!strcmp(cmd, "capacity")) ret_val = (ec_chip->i2c_dm_battery[14] << 8 ) | ec_chip->i2c_dm_battery[13]; else if (!strcmp(cmd, "remaining_capacity")) ret_val = (ec_chip->i2c_dm_battery[16] << 8 ) | ec_chip->i2c_dm_battery[15]; else if (!strcmp(cmd, "avg_time_to_empty")) ret_val = (ec_chip->i2c_dm_battery[18] << 8 ) | ec_chip->i2c_dm_battery[17]; else if (!strcmp(cmd, "avg_time_to_full")) ret_val = (ec_chip->i2c_dm_battery[20] << 8 ) | ec_chip->i2c_dm_battery[19]; else { ASUSPEC_ERR("Unknown command\n"); ret_val = -2; } ASUSPEC_INFO("cmd %s, return %d\n", cmd, ret_val); return ret_val; } }
static int asuspec_irq_ec_apwake(struct i2c_client *client) { int rc = 0 ; unsigned gpio = asuspec_apwake_gpio; int irq = gpio_to_irq(gpio); const char* label = "asuspec_apwake" ; ASUSPEC_INFO("GPIO = %d, irq = %d\n", gpio, irq); ASUSPEC_INFO("GPIO = %d , state = %d\n", gpio, gpio_get_value(gpio)); tegra_gpio_enable(gpio); rc = gpio_request(gpio, label); if (rc) { ASUSPEC_ERR("gpio_request failed for input %d\n", gpio); goto err_request_input_gpio_failed; } rc = gpio_direction_input(gpio) ; if (rc) { ASUSPEC_ERR("gpio_direction_input failed for input %d\n", gpio); goto err_gpio_direction_input_failed; } ASUSPEC_INFO("GPIO = %d , state = %d\n", gpio, gpio_get_value(gpio)); rc = request_irq(irq, asuspec_interrupt_handler,/*IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_TRIGGER_HIGH|*/IRQF_TRIGGER_LOW, label, client); if (rc < 0) { ASUSPEC_ERR("Could not register for %s interrupt, irq = %d, rc = %d\n", label, irq, rc); rc = -EIO; goto err_gpio_request_irq_fail ; } enable_irq_wake(gpio_to_irq(asuspec_apwake_gpio)); ASUSPEC_INFO("request irq = %d, rc = %d\n", irq, rc); return 0 ; err_gpio_request_irq_fail: gpio_free(gpio); err_gpio_direction_input_failed: err_request_input_gpio_failed : return rc; return 0 ; }
static void asuspec_enter_s3_work_function(struct work_struct *dat) { int ret_val = 0; int i = 0; mutex_lock(&ec_chip->state_change_lock); if (ec_chip->op_mode){ ASUSPEC_ERR("It's not allowed to access dockram under FW update mode.\n"); mutex_unlock(&ec_chip->state_change_lock); return ; } if (ec_chip->pad_pid == TEGRA3_PROJECT_P1801) asuspec_storage_info_update(); ec_chip->ec_in_s3 = 1; for ( i = 0; i < 3; i++ ){ ret_val = asuspec_dockram_read_data(0x0A); if (ret_val < 0){ ASUSPEC_ERR("fail to get control flag\n"); msleep(100); } else break; } ec_chip->i2c_dm_data[0] = 8; ec_chip->i2c_dm_data[5] = ec_chip->i2c_dm_data[5] | 0x02; for ( i = 0; i < 3; i++ ){ ret_val = asuspec_dockram_write_data(0x0A,9); if (ret_val < 0){ ASUSPEC_ERR("Send s3 command fail\n"); msleep(100); } else { ASUSPEC_NOTICE("EC in S3\n"); break; } } mutex_unlock(&ec_chip->state_change_lock); }
static int asuspec_i2c_write_data(struct i2c_client *client, u16 data) { int ret = 0; if (ec_chip->op_mode){ ASUSPEC_ERR("It's not allowed to access ec under FW update mode.\n"); return -1; } if (ec_chip->i2c_err_count > ASUSPEC_I2C_ERR_TOLERANCE){ return -3; } ret = i2c_smbus_write_word_data(client, 0x64, data); if (ret < 0) { ASUSPEC_ERR("Fail to write data, status %d\n", ret); } else { ec_chip->i2c_err_count = 0; } return ret; }
int asuspec_is_usb_charger(int charger_enable){ int ret = 0; if (ec_chip->ec_in_s3){ asuspec_send_ec_req(); msleep(200); } ret = asuspec_dockram_read_data(0x0A); if (ret < 0){ ASUSPEC_ERR("Fail to access control flag info.\n"); return ret; } ec_chip->i2c_dm_data[0] = 8; if (charger_enable){ ec_chip->i2c_dm_data[6] = ec_chip->i2c_dm_data[5] | 0x01; } else { ec_chip->i2c_dm_data[6] = ec_chip->i2c_dm_data[5] & 0xFE; } ret = asuspec_dockram_write_data(0x0A,9); mod_timer(&ec_chip->asuspec_timer,jiffies+(HZ * 1)); return ret; }
static int __devinit asuspec_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err = 0; ASUSPEC_INFO("asuspec probe\n"); err = sysfs_create_group(&client->dev.kobj, &asuspec_smbus_group); if (err) { ASUSPEC_ERR("Unable to create the sysfs\n"); goto exit; } ec_chip = kzalloc(sizeof (struct asuspec_chip), GFP_KERNEL); if (!ec_chip) { ASUSPEC_ERR("Memory allocation fails\n"); err = -ENOMEM; goto exit; } ec_chip->pad_pid = tegra3_get_project_id(); i2c_set_clientdata(client, ec_chip); ec_chip->client = client; ec_chip->client->driver = &asuspec_driver; ec_chip->client->flags = 1; init_timer(&ec_chip->asuspec_timer); ec_chip->asuspec_timer.function = asuspec_enter_s3_timer; wake_lock_init(&ec_chip->wake_lock, WAKE_LOCK_SUSPEND, "asuspec_wake"); mutex_init(&ec_chip->lock); mutex_init(&ec_chip->irq_lock); mutex_init(&ec_chip->state_change_lock); ec_chip->ec_ram_init = 0; ec_chip->audio_recording = 0; ec_chip->status = 0; ec_chip->ec_in_s3 = 0; ec_chip->apwake_disabled = 0; ec_chip->storage_total = 0; ec_chip->storage_avail = 0; asuspec_dockram_init(client); cdev_add(asuspec_cdev,asuspec_dev,1) ; ec_chip->pad_sdev.name = PAD_SDEV_NAME; ec_chip->pad_sdev.print_name = asuspec_switch_name; ec_chip->pad_sdev.print_state = asuspec_switch_state; if(switch_dev_register(&ec_chip->pad_sdev) < 0){ ASUSPEC_ERR("switch_dev_register for pad failed!\n"); } switch_set_state(&ec_chip->pad_sdev, 0); ec_chip->apower_sdev.name = APOWER_SDEV_NAME; ec_chip->apower_sdev.print_name = apower_switch_name; ec_chip->apower_sdev.print_state = apower_switch_state; ec_chip->apower_state = 0; if(switch_dev_register(&ec_chip->apower_sdev) < 0){ ASUSPEC_ERR("switch_dev_register for apower failed!\n"); } switch_set_state(&ec_chip->apower_sdev, ec_chip->apower_state); asuspec_wq = create_singlethread_workqueue("asuspec_wq"); INIT_DELAYED_WORK_DEFERRABLE(&ec_chip->asuspec_work, asuspec_work_function); INIT_DELAYED_WORK_DEFERRABLE(&ec_chip->asuspec_init_work, asuspec_init_work_function); INIT_DELAYED_WORK_DEFERRABLE(&ec_chip->asuspec_fw_update_work, asuspec_fw_update_work_function); INIT_DELAYED_WORK_DEFERRABLE(&ec_chip->asuspec_enter_s3_work, asuspec_enter_s3_work_function); INIT_DELAYED_WORK_DEFERRABLE(&asuspec_stress_work, asuspec_stresstest_work_function); asuspec_irq_ec_request(client); asuspec_irq_ec_apwake(client); queue_delayed_work(asuspec_wq, &ec_chip->asuspec_init_work, 0); return 0; exit: return err; }