static void twl4030_poweroff(void) { u8 uninitialized_var(val); int err; int i = 0; #if defined(CONFIG_AP2MODEM_VIATELECOM) extern void ap_poweroff_modem(void); ap_poweroff_modem( ); #endif /* Clear the STARTON_VBAT and STARTON_SWBUG * STARTON_VBAT will cause the auto reboot if battery insert; * STARTON_SWBUG will cause the auto reboot if watchdog has been expired * Mark the STARTON_PWON, which enable switch on transition if power on has been pressed */ twl4030_enable_write(); for(i=0; i<3; i++){ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, PWR_CFG_P1_TRANSITION + i); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030 PM_MASTER PWR_CFG_P%d_TRANSITION\n", err, i+1); goto fail; } val &= (~(STARTON_SWBUG | STARTON_VBAT)); val |= STARTON_PWON | STARTON_RTC | STARTON_CHG; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, PWR_CFG_P1_TRANSITION + i); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030 PM_MASTER PWR_CFG_P%d_TRANSITION\n", err, i+1); goto fail; } } twl4030_disable_write(); #if 0 /*fire the watchdog*/ val = WATCHDOG_FIRE; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, WATCHDOG_CFG); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030 PM_MASTER PWR_CFG_P%d_TRANSITION\n", err, i+1); goto fail ; } #endif /* Make sure SEQ_OFFSYNC is set so that all the res goes to wait-on */ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, CFG_P123_TRANSITION); if (err) { pr_warning("I2C error %d while reading TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err); return; } val |= SEQ_OFFSYNC; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, CFG_P123_TRANSITION); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err); return; } err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, PWR_P1_SW_EVENTS); if (err) { pr_warning("I2C error %d while reading TWL4030 PM_MASTER P1_SW_EVENTS\n", err); return; } val |= PWR_STOPON_POWERON | PWR_DEVOFF; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, PWR_P1_SW_EVENTS); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_MASTER P1_SW_EVENTS\n", err); return; } return; fail: printk(KERN_ERR "Fail to power off the system.\n"); while(1) ; }
static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) { int rconfig_addr; int err; u8 type; u8 grp; u8 remap; if (rconfig->resource > TOTAL_RESOURCES) { pr_err("TWL4030 Resource %d does not exist\n", rconfig->resource); return -EINVAL; } rconfig_addr = res_config_addrs[rconfig->resource]; /* Set resource group */ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp, rconfig_addr + DEV_GRP_OFFSET); if (err) { pr_err("TWL4030 Resource %d group could not be read\n", rconfig->resource); return err; } if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) { grp &= ~DEV_GRP_MASK; grp |= rconfig->devgroup << DEV_GRP_SHIFT; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, grp, rconfig_addr + DEV_GRP_OFFSET); if (err < 0) { pr_err("TWL4030 failed to program devgroup\n"); return err; } } /* Set resource types */ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type, rconfig_addr + TYPE_OFFSET); if (err < 0) { pr_err("TWL4030 Resource %d type could not be read\n", rconfig->resource); return err; } if (rconfig->type != TWL4030_RESCONFIG_UNDEF) { type &= ~TYPE_MASK; type |= rconfig->type << TYPE_SHIFT; } if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) { type &= ~TYPE2_MASK; type |= rconfig->type2 << TYPE2_SHIFT; } err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, type, rconfig_addr + TYPE_OFFSET); if (err < 0) { pr_err("TWL4030 failed to program resource type\n"); return err; } /* Set remap states */ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap, rconfig_addr + REMAP_OFFSET); if (err < 0) { pr_err("TWL4030 Resource %d remap could not be read\n", rconfig->resource); return err; } if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) { remap &= ~OFF_STATE_MASK; remap |= rconfig->remap_off << OFF_STATE_SHIFT; } if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) { remap &= ~SLEEP_STATE_MASK; remap |= rconfig->remap_off << SLEEP_STATE_SHIFT; } err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, remap, rconfig_addr + REMAP_OFFSET); if (err < 0) { pr_err("TWL4030 failed to program remap\n"); return err; } return 0; }
static void twl6030charger_ctrl_work_handler(struct work_struct *work) { struct charger_device_info *di = container_of(work, struct charger_device_info, twl6030charger_ctrl_work.work); int ret; int n_usbic_state; int charger_fault = 0; long int events; u8 stat_toggle, stat_reset, stat_set = 0; u8 charge_state = 0; u8 present_charge_state = 0; u8 ac_or_vbus, no_ac_and_vbus = 0; u8 hw_state = 0, temp = 0; dev_dbg(di->dev, "[TA] %s start\n",__func__); clear_charge_start_time(); /* read charger controller_stat1 */ ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &present_charge_state, CONTROLLER_STAT1); if (ret) return 0; twl_i2c_read_u8(TWL6030_MODULE_ID0, &hw_state, STS_HW_CONDITIONS); charge_state = di->stat1; stat_toggle = charge_state ^ present_charge_state; stat_set = stat_toggle & present_charge_state; stat_reset = stat_toggle & charge_state; no_ac_and_vbus = !((present_charge_state) & (VBUS_DET | VAC_DET)); ac_or_vbus = charge_state & (VBUS_DET | VAC_DET); if (no_ac_and_vbus && ac_or_vbus) { dev_dbg(di->dev, "[TA] No Charging source\n"); /* disable charging when no source present */ } charge_state = present_charge_state; di->stat1 = present_charge_state; if (stat_reset & VBUS_DET) { /* On a USB detach, UNMASK VBUS OVP if masked*/ twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &temp, CHARGERUSB_INT_MASK); if (temp & MASK_MCHARGERUSB_FAULT) twl_i2c_write_u8(TWL6030_MODULE_CHARGER, (temp & ~MASK_MCHARGERUSB_FAULT), CHARGERUSB_INT_MASK); dev_dbg(di->dev, "[TA] Charging source removed\n"); change_cable_status(POWER_SUPPLY_TYPE_BATTERY, di); #ifdef CONFIG_DYNAMIC_TSP_SETTINGS_FOR_CHARGER_STATE set_tsp_for_ta_detect(0); #endif } if (stat_set & VBUS_DET) { /* In HOST mode (ID GROUND) when a device is connected, Mask * VBUS OVP interrupt and do no enable usb charging */ if (hw_state & STS_USB_ID) { twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &temp, CHARGERUSB_INT_MASK); if (!(temp & MASK_MCHARGERUSB_FAULT)) twl_i2c_write_u8(TWL6030_MODULE_CHARGER, (temp | MASK_MCHARGERUSB_FAULT), CHARGERUSB_INT_MASK); } else { n_usbic_state = get_real_usbic_state(); dev_dbg(di->dev, "[TA] cable_detection_isr handler. usbic_state: %d\n", n_usbic_state); switch (n_usbic_state) { case MICROUSBIC_5W_CHARGER: case MICROUSBIC_TA_CHARGER: case MICROUSBIC_USB_CHARGER: case MICROUSBIC_PHONE_USB: case MICROUSBIC_USB_CABLE: case MICROUSBIC_MHL_CHARGER: case MICROUSBIC_JIG_USB_ON: if (sec_bci->charger.cable_status == POWER_SUPPLY_TYPE_USB || sec_bci->charger.cable_status == POWER_SUPPLY_TYPE_MAINS ){ dev_dbg(di->dev, "[TA] Already Plugged\n"); break; } /*Check VF */ sec_bci->battery.battery_vf_ok = check_battery_vf(); /*TA or USB or MHL is inserted */ if (n_usbic_state == MICROUSBIC_USB_CABLE) { //current : 395mA dev_dbg(di->dev,"[TA] USB CABLE PLUGGED\n"); change_cable_status(POWER_SUPPLY_TYPE_USB, di); #ifdef CONFIG_DYNAMIC_TSP_SETTINGS_FOR_CHARGER_STATE set_tsp_for_ta_detect(1); #endif } else if (n_usbic_state == MICROUSBIC_MHL_CHARGER) { //current : 395mA dev_dbg(di->dev,"[TA] MHL CABLE PLUGGED\n"); change_cable_status(POWER_SUPPLY_TYPE_USB, di); #ifdef CONFIG_DYNAMIC_TSP_SETTINGS_FOR_CHARGER_STATE set_tsp_for_ta_detect(1); #endif } else if (n_usbic_state == MICROUSBIC_JIG_USB_ON) { //current : 1000mA dev_dbg(di->dev,"[TA] JIG_USB_ON CABLE PLUGGED\n"); change_cable_status(POWER_SUPPLY_TYPE_MAINS, di); #ifdef CONFIG_DYNAMIC_TSP_SETTINGS_FOR_CHARGER_STATE set_tsp_for_ta_detect(1); #endif } else { //current : 1000mA dev_dbg(di->dev,"[TA] CHARGER CABLE PLUGGED\n"); change_cable_status(POWER_SUPPLY_TYPE_MAINS, di); #ifdef CONFIG_DYNAMIC_TSP_SETTINGS_FOR_CHARGER_STATE set_tsp_for_ta_detect(1); #endif } break; default: ; } } } if (sec_bci->charger.prev_cable_status == -1 && sec_bci->charger.cable_status == -1) { dev_dbg(di->dev,"[TA] Fisrt time after bootig.\n"); change_cable_status(POWER_SUPPLY_TYPE_BATTERY, di); #ifdef CONFIG_DYNAMIC_TSP_SETTINGS_FOR_CHARGER_STATE set_tsp_for_ta_detect(0); #endif } if (stat_set & CONTROLLER_STAT1_FAULT_WDG) { // charger_fault = 1; dev_dbg(di->dev, "Fault watchdog fired\n"); } if (stat_reset & CONTROLLER_STAT1_FAULT_WDG) dev_dbg(di->dev, "Fault watchdog recovered\n"); if (stat_set & CONTROLLER_STAT1_BAT_REMOVED) dev_dbg(di->dev, "Battery removed\n"); if (stat_reset & CONTROLLER_STAT1_BAT_REMOVED) dev_dbg(di->dev, "Battery inserted\n"); if (stat_set & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) dev_dbg(di->dev, "Battery temperature overrange\n"); if (stat_reset & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) dev_dbg(di->dev, "Battery temperature within range\n"); if (charger_fault) { change_charge_status(POWER_SUPPLY_STATUS_NOT_CHARGING); dev_err(di->dev, "Charger Fault stop charging\n"); } }
void bat_monitor_work_func(struct work_struct *work) { struct bq27541_info *di = container_of(work, struct bq27541_info, bat_monitor_work.work); int err = 0; int new_value=0; int change=0; //For dead battery if(di->err_count>=15){ printk("bat:%s get i2c error\n",__func__); err=bq27x00_battery_voltage(di,&new_value); if (err){ queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(10000 * 1)); blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_I2C_ERROR, NULL); di->health = POWER_SUPPLY_HEALTH_UNKNOWN; power_supply_changed(&di->bat); }else{//dead battery is wake up printk("bat:%s dead battery is wake up\n",__func__); di->err_count=0; queue_delayed_work(bat_work_queue,&di->bat_monitor_work,0); blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_I2C_NORMAL, NULL); di->health = POWER_SUPPLY_HEALTH_GOOD; power_supply_changed(&di->bat); } }else{ /* * We query the four most important variables frequently: * * temperature, voltage, capacity, status * * These four are used by various code in upper layers for * power management. The rest of the variables are not that * important or do not change much over time so we do not * need to query them too often */ if (bq27x00_battery_temperature(di, &new_value)) { di->err_count++; } else { if (new_value != di->temp) { di->temp = new_value; change = 1; bat_temp_charge_protect(di); } } if (bq27x00_battery_voltage(di, &new_value)) { di->err_count++; } else { if (new_value != di->voltage) { di->voltage = new_value; change = 1; //Low battery protection //If android with weak battery has some problem and not be shutdown then driver need to turn off the system. if((di->voltage <= HARD_LOW_VOLTAGE_THRESHOLD) && (di->status==POWER_SUPPLY_STATUS_DISCHARGING)) blocking_notifier_call_chain(¬ifier_list, EVENT_WEAK_BATTERY, NULL); } } if (bq27x00_battery_rsoc(di, &new_value)) { di->err_count++; } else { if (new_value != di->capacity) { di->capacity = new_value; change = 1; //Recharge event if((di->status==POWER_SUPPLY_STATUS_NOT_CHARGING) && (di->capacity<=RECHARGE_THRESHOLD)) blocking_notifier_call_chain(¬ifier_list, EVENT_RECHARGE_BATTERY, NULL); } } if (bq27x00_battery_status(di, &new_value)) { di->err_count++; } else { if (new_value!=di->status) { di->status = new_value; change = 1; //Full charge protectition event if (di->status == POWER_SUPPLY_STATUS_FULL) blocking_notifier_call_chain(¬ifier_list, EVENT_FULL_BATTERY, NULL); } } /* * Average current is also required to be * queried frequently for factory testing */ if (bq27x00_battery_current(di, &new_value)){ di->err_count++; } else { if (new_value != di->current_avg) { di->current_avg=new_value; change = 1; } } if (++di->long_count != BQ27541_LONG_COUNT) { /* Done with the important ones, skip the rest for now */ goto update_status; } else { di->long_count = 0; } new_value=twl_get_batntc(); if(new_value!=di->ntc_temp){ if((di->ntc_temp==0) && (new_value>0)) blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_NTC_NORMAL, NULL); di->ntc_temp=new_value; if(di->ntc_temp==0) blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_NTC_ZERO, NULL); } bq27x00_read(REG_FULL_AVAILABLE_CHARGE, &g_full_available_capacity, 0, di); if (bq27x00_battery_health(di, &new_value)) { di->err_count++; } else { if (new_value != di->health) { di->health = new_value; change = 1; } } /* Query TimeToEmpty() register */ if (bq27x00_battery_time_to_empty(di, &new_value)) { di->err_count++; } else if (new_value != di->time_to_empty) { di->time_to_empty = new_value; change = 1; } /* Query TimeToFull() register */ if (bq27x00_battery_time_to_full(di, &new_value)) { di->err_count++; } else if (new_value != di->time_to_full) { di->time_to_full = new_value; change = 1; } /* Query CycleCount() register */ if (bq27x00_battery_cycle_count(di, &new_value)) { di->err_count++; } else if (new_value != di->cycle_count) { di->cycle_count = new_value; change = 1; } /* Query AveragePower() register */ if (bq27x00_battery_average_power(di, &new_value)) { di->err_count++; } else if (new_value != di->average_power) { di->average_power = new_value; change = 1; } /* Query AvailableEnergy() register */ if (bq27x00_battery_available_energy(di, &new_value)) { di->err_count++; } else if (new_value != di->available_energy) { di->available_energy = new_value; change = 1; } /* Query RemainingCapacity() register */ if (bq27x00_battery_remaining_charge(di, &new_value)) { di->err_count++; } else if (new_value != di->remaining_charge) { di->remaining_charge = new_value; change = 1; } /* Query FullChargeCapacity() register */ if (bq27x00_battery_full_charge(di, &new_value)) { di->err_count++; } else if (new_value != di->full_charge) { di->full_charge = new_value; change = 1; } /* Query FullAvailableCapacity() register */ if (bq27x00_battery_full_charge_uncompensated(di, &new_value)) { di->err_count++; } else if (new_value != di->full_charge_uncompensated) { di->full_charge_uncompensated = new_value; change = 1; } if (++di->manufacturer_id_read_count != 2) { goto update_status; } else { di->manufacturer_id_read_count = 0; } /* Check for manufacturer ID every minute */ new_value = check_manufacturer(di); if (new_value != di->manufacturer){ di->manufacturer = new_value; change = 1; if (di->manufacturer >= 0) blocking_notifier_call_chain(¬ifier_list, EVENT_RECOGNIZE_BATTERY, NULL); if (di->manufacturer == NOT_RECOGNIZE) blocking_notifier_call_chain(¬ifier_list, EVENT_NOT_RECOGNIZE_BATTERY, NULL); if (di->manufacturer == UNKNOW) blocking_notifier_call_chain(¬ifier_list, EVENT_UNKNOW_BATTERY, NULL); } update_status: if (change) { power_supply_changed(&di->bat); // LED function u8 value = 0; if ((di->disable_led == 0) && !twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03)) { if ((di->status == POWER_SUPPLY_STATUS_CHARGING) && (value & (1 << 2))) { if(di->capacity < 90) { /* * Battery being charged, capacity < 90%: Amber LED */ omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 255); } else { /* * Battery being charged, capacity >= 90%: Green LED */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } } else if (di->status == POWER_SUPPLY_STATUS_FULL) { if (value & (1 << 2)) { /* Set to green if connected to USB */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } else { omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 0); } } } } if(di->err_count>=15){ printk("bat:%s get i2c error\n",__func__); queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(10000 * 1)); }else queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(5000 * 1)); } }
static int twl4030_power_probe(struct platform_device *pdev) { struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; int err = 0; int err2 = 0; u8 val; if (!pdata && !node) { dev_err(&pdev->dev, "Platform data is missing\n"); return -EINVAL; } err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, TWL4030_PM_MASTER_PROTECT_KEY); err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, TWL4030_PM_MASTER_PROTECT_KEY); if (err) { pr_err("TWL4030 Unable to unlock registers\n"); return err; } if (pdata) { /* TODO: convert to device tree */ err = twl4030_power_configure_scripts(pdata); if (err) { pr_err("TWL4030 failed to load scripts\n"); goto relock; } err = twl4030_power_configure_resources(pdata); if (err) { pr_err("TWL4030 failed to configure resource\n"); goto relock; } } /* Board has to be wired properly to use this feature */ if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) { /* Default for SEQ_OFFSYNC is set, lets ensure this */ err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, TWL4030_PM_MASTER_CFG_P123_TRANSITION); if (err) { pr_warning("TWL4030 Unable to read registers\n"); } else if (!(val & SEQ_OFFSYNC)) { val |= SEQ_OFFSYNC; err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, TWL4030_PM_MASTER_CFG_P123_TRANSITION); if (err) { pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); goto relock; } } pm_power_off = twl4030_power_off; } relock: err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, TWL4030_PM_MASTER_PROTECT_KEY); if (err2) { pr_err("TWL4030 Unable to relock registers\n"); return err2; } return err; }
int twl6030_mmc_card_detect_config(void) { int ret; u8 reg_val = 0; /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, REG_INT_MSK_LINE_B); twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, REG_INT_MSK_STS_B); /* * Initially Configuring MMC_CTRL for receiving interrupts & * Card status on TWL6030 for MMC1 */ ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); if (ret < 0) { pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); return ret; } /* LGE_SJIT 2011-11-28 [[email protected]] 2011-11-28 * LGE_CHANGE [[email protected]] 2011-07-19, from p940 * * Leak the current 40mA on off state */ #if defined(CONFIG_MMC_OMAP_HS_VMMC_AUTO_OFF) reg_val |= VMMC_AUTO_OFF; #ifndef CONFIG_MACH_LGE_MMC_COVER reg_val |= SW_FC; #else reg_val |= SW_FC; //MOD #endif #else reg_val &= ~VMMC_AUTO_OFF; #ifndef CONFIG_MACH_LGE_MMC_COVER reg_val |= SW_FC; #else reg_val &= ~SW_FC; #endif #endif // reg_val |= SW_FC; ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); if (ret < 0) { pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); return ret; } /* Configuring PullUp-PullDown register */ ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_CFG_INPUT_PUPD3); if (ret < 0) { pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", ret); return ret; } reg_val &= ~(MMC_PU | MMC_PD); ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_CFG_INPUT_PUPD3); if (ret < 0) { pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", ret); return ret; } ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, (MMC_MINS_DEB_MASK | MMC_MEXT_DEB_MASK), TWL6030_MMCDEBOUNCING); if (ret < 0){ pr_err("twl6030: Failed to write MMC_MEXT_DEB_MASK %d\n", ret); return ret; } return 0; }
static int twl4030_bci_read(u8 reg, u8 *val) { return twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, val, reg); }
/** * @brief omap3evm_set_mux - Sets mux to enable/disable signal routing to * different peripherals present on new EVM board * IMPORTANT - This function will take care of writing appropriate values for * active low signals as well * * @param mux_id - enum, mux id to enable/disable * @param value - enum, ENABLE_MUX for enabling and DISABLE_MUX for disabling * * @return result of operation - 0 is success */ static int omap3evm_set_mux(enum omap3evmdc_mux mux_id, enum config_mux value) { static int is_init_done = 0; unsigned char val; int err = 0; if (unlikely(mux_id >= NUM_MUX)) { printk(KERN_ERR MODULE_NAME ": Invalid mux id\n"); return -EPERM; } if (is_init_done == 0) { /*FIXME: Need to follow standard GPIO API's to control * TWL4030 GPIO. */ /* Enable TWL GPIO Module */ twl_i2c_write_u8(TWL4030_MODULE_GPIO, 0x04, REG_GPIO_CTRL); /* First Level Enable GPIO */ /* Configure GPIO2 as output */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATADIR1); val |= 0x04; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATADIR1); /* Set GPIO-2 pull-up */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIOPUPDCTR1); val |= 0x20; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIOPUPDCTR1); /* Set GPIO-2 = 0 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT1); val &= ~0x04; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT1); /* Configure GPIO8 as output*/ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATADIR2); val |= 0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATADIR2); /* GPIO-8 pull down */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIOPUPDCTR3); val |= 0x01; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIOPUPDCTR3); /* Assert the reset signal */ gpio_set_value(GPIO98_VID_DEC_RES, 0); mdelay(5); gpio_set_value(GPIO98_VID_DEC_RES, 1); } switch (mux_id) { case MUX_TVP5146: if (ENABLE_MUX == value) { /* Set GPIO8 = 0 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT2); val &= ~0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT2); gpio_set_value(nCAM_VD_SEL, 1); } else { /* Set GPIO8 = 0 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT2); val |= 0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT2); } break; case MUX_CAMERA_SENSOR: if (ENABLE_MUX == value) { /* Set GPIO8 = 0 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT2); val &= ~0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT2); gpio_set_value(nCAM_VD_SEL, 0); } else { /* Set GPIO8 = 0 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT2); val |= 0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT2); } break; case MUX_EXP_CAMERA_SENSOR: if (ENABLE_MUX == value) { /* Set GPIO8 = 1 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT2); val |= 0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT2); } else { /* Set GPIO8 = 0 */ twl_i2c_read_u8(TWL4030_MODULE_GPIO, &val, REG_GPIODATAOUT2); val &= ~0x1; twl_i2c_write_u8(TWL4030_MODULE_GPIO, val, REG_GPIODATAOUT2); } break; case NUM_MUX: default: printk(KERN_ERR "Invalid mux id\n"); err = -EPERM; } return err; }
void __devinit twl4030_power_init(struct twl4030_power_data *twl4030_scripts) { int err = 0; int i; struct twl4030_resconfig *resconfig; u8 val, address = twl4030_start_script_address; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, TWL4030_PM_MASTER_PROTECT_KEY); if (err) goto unlock; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, TWL4030_PM_MASTER_PROTECT_KEY); if (err) goto unlock; for (i = 0; i < twl4030_scripts->num; i++) { err = load_twl4030_script(twl4030_scripts->scripts[i], address); if (err) goto load; address += twl4030_scripts->scripts[i]->size; } resconfig = twl4030_scripts->resource_config; if (resconfig) { while (resconfig->resource) { err = twl4030_configure_resource(resconfig); if (err) goto resource; resconfig++; } } if (twl4030_scripts->use_poweroff && !pm_power_off) { err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, TWL4030_PM_MASTER_CFG_P123_TRANSITION); if (err) { pr_warning("TWL4030 Unable to read registers\n"); } else if (!(val & SEQ_OFFSYNC)) { val |= SEQ_OFFSYNC; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, TWL4030_PM_MASTER_CFG_P123_TRANSITION); if (err) { pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); goto relock; } } pm_power_off = twl4030_power_off; } relock: err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, TWL4030_PM_MASTER_PROTECT_KEY); if (err) pr_err("TWL4030 Unable to relock registers\n"); return; unlock: if (err) pr_err("TWL4030 Unable to unlock registers\n"); return; load: if (err) pr_err("TWL4030 failed to load scripts\n"); return; resource: if (err) pr_err("TWL4030 failed to configure resource\n"); return; }
static int __init sdp4430_soc_init(void) { struct i2c_adapter *adapter; u8 gpoctl; int ret; if (!machine_is_omap_4430sdp() && !machine_is_omap4_panda() && !machine_is_omap_tabletblaze()) { pr_debug("Not SDP4430, BlazeTablet or PandaBoard!\n"); return -ENODEV; } printk(KERN_INFO "SDP4430 SoC init\n"); if (machine_is_omap_4430sdp()) snd_soc_sdp4430.name = "SDP4430"; else if (machine_is_omap4_panda()) snd_soc_sdp4430.name = "Panda"; else if (machine_is_omap_tabletblaze()) snd_soc_sdp4430.name = "Tablet44xx"; sdp4430_snd_device = platform_device_alloc("soc-audio", -1); if (!sdp4430_snd_device) { printk(KERN_ERR "Platform device allocation failed\n"); return -ENOMEM; } ret = snd_soc_register_dais(&sdp4430_snd_device->dev, dai, ARRAY_SIZE(dai)); if (ret < 0) goto err; platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430); ret = platform_device_add(sdp4430_snd_device); if (ret) goto err_dev; twl6040_codec = snd_soc_card_get_codec(&snd_soc_sdp4430, "twl6040-codec"); if(twl6040_codec <= 0) { printk(KERN_ERR "sdp4430: could not find `twl6040-codec`\n"); ret = -ENODEV; goto err_dev; } av_switch_reg = regulator_get(&sdp4430_snd_device->dev, "av-switch"); if (IS_ERR(av_switch_reg)) { ret = PTR_ERR(av_switch_reg); printk(KERN_ERR "couldn't get AV Switch regulator %d\n", ret); goto err_dev; } /* enable tps6130x */ ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &gpoctl, TWL6040_REG_GPOCTL); if (ret) { printk(KERN_ERR "i2c read error\n"); goto i2c_err; } ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, gpoctl | TWL6040_GPO2, TWL6040_REG_GPOCTL); if (ret) { printk(KERN_ERR "i2c write error\n"); goto i2c_err; } adapter = i2c_get_adapter(TPS6130X_I2C_ADAPTER); if (!adapter) { printk(KERN_ERR "can't get i2c adapter\n"); ret = -ENODEV; goto adp_err; } tps6130x_client = i2c_new_device(adapter, &tps6130x_hwmon_info); if (!tps6130x_client) { printk(KERN_ERR "can't add i2c device\n"); ret = -ENODEV; goto tps_err; } /* Only configure the TPS6130x on SDP4430 */ if (machine_is_omap_4430sdp() || machine_is_omap_tabletblaze()) sdp4430_tps6130x_configure(); i2c_put_adapter(adapter); return ret; tps_err: i2c_put_adapter(adapter); adp_err: twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, gpoctl, TWL6040_REG_GPOCTL); i2c_err: regulator_put(av_switch_reg); err_dev: snd_soc_unregister_dais(&sdp4430_snd_device->dev, ARRAY_SIZE(dai)); err: platform_device_put(sdp4430_snd_device); return ret; }
struct pwm_device *pwm_request(int pwm_id, const char *label) { u8 stat; u8 val; int ret; struct pwm_device *pwm; pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); if (pwm == NULL) { pr_err("%s: failed to allocate memory\n", label); return NULL; } pwm->label = label; pwm->pwm_id = pwm_id; pwm->duty_cycle = -1; switch (pwm_id) { case 3: /* Custom PWM2 */ ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_TOGGLE3); if (ret < 0) goto fail; ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, (val | TOGGLE3_PWM2_SET | TOGGLE3_PWM2_CLK_EN), TWL6030_TOGGLE3); break; case 2: /* Custom PWM1 */ ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_TOGGLE3); if (ret < 0) goto fail; ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, (val | TOGGLE3_PWM1_SET | TOGGLE3_PWM1_CLK_EN), TWL6030_TOGGLE3); break; case 1: /* LED PWM */ /* Configure PWM */ ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &stat, LED_PWM_CTRL2); val = PWM_CTRL2_DIS_PD | PWM_CTRL2_SRC_VBUS | PWM_CTRL2_MODE_HW; /* Setup led current to 5mA if config is not set */ if (stat & (0x03 << 4)) val |= (stat & (0x03 << 4)); else val |= PWM_CTRL2_CURR_03; ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); if (ret < 0) goto fail; break; } return pwm; fail: pr_err("%s: Failed to configure PWM, Error %d\n", pwm->label, ret); kfree(pwm); return NULL; }
static ssize_t summit_proc_write(struct file *filp, const char *buff,unsigned long len, void *data) { struct summit_smb347_info *di=data; struct regulator *p_regulator = regulator_get(NULL, "usb-phy"); //printk(KERN_INFO "%s\n",__func__); u32 reg_val,value; // void __iomem *addr = NULL; int event = USB_EVENT_VBUS; struct clk *phyclk; struct clk *clk48m; struct clk *clk32k; int hw_state=0; char messages[256], vol[256]; phyclk = clk_get(NULL, "ocp2scp_usb_phy_ick"); if (IS_ERR(phyclk)) { pr_warning("cannot clk_get ocp2scp_usb_phy_ick\n"); return PTR_ERR(phyclk); } clk48m = clk_get(NULL, "ocp2scp_usb_phy_phy_48m"); if (IS_ERR(clk48m)) { pr_warning("cannot clk_get ocp2scp_usb_phy_phy_48m\n"); clk_put(phyclk); return PTR_ERR(clk48m); } clk32k = clk_get(NULL, "usb_phy_cm_clk32k"); if (IS_ERR(clk32k)) { pr_warning("cannot clk_get usb_phy_cm_clk32k\n"); clk_put(phyclk); clk_put(clk48m); return PTR_ERR(clk32k); } if (len > 256) len = 256; if (copy_from_user(messages, buff, len)) return -EFAULT; if ('-' == messages[0]) { /* set the register index */ memcpy(vol, messages+1, len-1); index = (int) simple_strtoul(vol, NULL, 16); printk(KERN_INFO"%s:set register 0x%x\n",__func__, index); }else if('+'==messages[0]) { // set the register value memcpy(vol, messages+1, len-1); reg_val = (int)simple_strtoul(vol, NULL, 16); //you can read value from the register of hardwae in here i2c_smbus_write_byte_data(di->client, index, reg_val); printk(KERN_INFO"%s:register 0x%x: set value 0x%x\n",__func__, index, reg_val); }else if ('!' == messages[0]) { switch(messages[1]){ case 'a': //gpio_request(119, "ADO_SPK_ENABLE"); //gpio_direction_output(119, 0); value =i2c_smbus_read_byte_data(di->client,index); if (value < 0) { printk(KERN_INFO"error reading index=0x%x value=0x%x\n",index,value); } printk(KERN_INFO"%s:register 0x%x: return value 0x%x di->mbid=%d protect_enable=%d di->protect_event=0x%x\n",__func__, index, value,di->mbid,di->protect_enable,di->protect_event); break; case 'b': //regulator_disable(p_regulator); # if 0 twl_i2c_read_u8(TWL6030_MODULE_ID0, &hw_state, STS_HW_CONDITIONS); printk("hw_state=0x%x\n",hw_state); if(hw_state & STS_USB_ID){ printk("STS_USB_ID\n"); }else{ printk("NO STS_USB_ID\n"); } command=i2c_smbus_read_byte_data(di->client,COMMAND_A); printk("COMMAND_A=0x%x\n",command); #endif //printk("enable clock\n"); //clk_enable(phyclk); //clk_enable(clk48m); //clk_enable(clk32k); printk("phy power up"); __raw_writel(~PHY_PD, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x2300))); //summit_config_charge_current(di,FCC_2000mA,CONFIG_NO_CHANGE,CONFIG_NO_CHANGE); //charge_enable(di,1); break; case 'c': printk("disable clock\n"); clk_disable(phyclk); clk_disable(clk48m); clk_disable(clk32k); printk("phy power down"); __raw_writel(PHY_PD, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x2300))); //charge_enable(di,0); //di->event=EVENT_CHANGE_TO_ONDEMAND; //printk("%s event=%d %d \n",__func__,di->event,EVENT_CHANGE_TO_ONDEMAND); //fsm_stateTransform(di); //fsm_doAction(di); break; /* enable ocp2scp_usb_phy_ick,ocp2scp_usb_phy_phy_48m, ->4A0093E0 =0x101 usb_phy_cm_clk32k ->4A00 8640 =0x100 disable ->4A0093E0 =0x30100 ->4A00 8640 =0x0 */ case 'd': //di->event=EVENT_CHANGE_TO_INTERNAL_FSM; //printk("%s event=%d %d \n",__func__,di->event,EVENT_CHANGE_TO_ONDEMAND); //fsm_stateTransform(di); //fsm_doAction(di); printk("phy power up"); __raw_writel(0x101, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x93E0))); __raw_writel(0x100, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x8640))); __raw_writel(~PHY_PD, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x2300))); //switch_mode(di,USB1_MODE); break; case 'e': printk("phy power down"); __raw_writel(0x30100, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x93E0))); __raw_writel(0x0, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x8640))); __raw_writel(PHY_PD, OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x2300))); //switch_mode(di,USB5_MODE); break; case 'f': value=__raw_readl(OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x4120))); printk("%s : CM_CLKMODE_DPLL_CORE=0x%x\n",__func__,value); value=__raw_readl(OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x93E0))); printk("%s : CM_L3INIT_USBPHY_CLKCTRL=0x%x\n",__func__,value); value=__raw_readl(OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x8640))); printk("%s : CM_ALWON_USBPHY_CLKCTRL=0x%x\n",__func__,value); value=__raw_readl(OMAP2_L4_IO_ADDRESS(0x4a000000 + (0x2300))); printk("%s : CONTROL_DEV_CONF=0x%x\n",__func__,value); //switch_mode(di,HC_MODE); value=__raw_readl(OMAP2_L4_IO_ADDRESS(0x4a100000 + (0x620))); printk("%s : usb2phy=0x%x\n",__func__,value); break; case 'g': twl_i2c_write_u8(TWL6030_MODULE_ID0, 0x8 ,0xe5); twl_i2c_write_u8(TWL6030_MODULE_ID0, 0x18 ,0xa3); twl_i2c_write_u8(TWL6030_MODULE_ID0, 0x3f ,0xa1); twl_i2c_write_u8(TWL6030_MODULE_ID0, 0xe1 ,0xa2); # if 0 summit_charge_enable(di,0); summit_charge_enable(di,1); mdelay(10); summit_check_bmd(di); //charge_enable(di,0); #endif break; case '1': //summit_switch_mode(di,USB1_OR_15_MODE); summit_config_suspend_by_register(di,1); break; case '2': //summit_switch_mode(di,USB5_OR_9_MODE); summit_config_suspend_by_register(di,0); break; case '3': gpio_set_value(di->pin_susp, 0);printk(KERN_INFO "di->pin_susp=%d\n",di->pin_susp); break; case '4': gpio_set_value(di->pin_susp, 1);printk(KERN_INFO "di->pin_susp=%d\n",di->pin_susp); break; case '5': gpio_set_value(di->pin_en, 0);printk(KERN_INFO "di->pin_en=%d\n",di->pin_en); break; case '6': gpio_set_value(di->pin_en, 1);printk(KERN_INFO "di->pin_en=%d\n",di->pin_en); //summit_config_apsd(di,1); break; case '7': summit_config_aicl(di,0,4200); //summit_config_apsd(di,0); break; case '8': blocking_notifier_call_chain(&di->xceiv->notifier,USB_EVENT_NONE, di->xceiv->gadget); //summit_suspend_mode(di,1); break; case '9': //printk("power_source=%d\n",di->power_source); //di->power_source=4; summit_charger_reconfig(di); break; } } regulator_put(p_regulator); return len; }
static void twl4030_poweroff(void) { u8 val; int err; // Clear IT_ALARM bit in RTC_INTERRUPTS_REG [+] err = twl_i2c_read_u8(TWL4030_MODULE_RTC, &val, REG_RTC_INTERRUPT_REG); if (err) { printk(KERN_WARNING "I2C error %d while reading TWL4030" "REG_RTC_INTERRUPT_REG\n", err); return ; } val &= ~(0x01<<3); err = twl_i2c_write_u8(TWL4030_MODULE_RTC, val, REG_RTC_INTERRUPT_REG); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030" "REG_RTC_INTERRUPT_REG\n", err); return ; } #if 0 err = twl_i2c_read_u8(TWL4030_MODULE_RTC, &val, REG_RTC_INTERRUPT_REG); if (err) { printk(KERN_WARNING "I2C error %d while reading TWL4030" "REG_RTC_INTERRUPT_REG\n", err); return ; } printk("Clear IT ALARM bit in RTC INTERRUPT REG( = 0x%02x) Done!\n", val); #endif // Clear IT_ALARM bit in RTC_INTERRUPTS_REG [-] err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, PWR_P1_SW_EVENTS); if (err) { printk(KERN_WARNING "I2C error %d while reading TWL4030" "PM_MASTER P1_SW_EVENTS\n", err); return ; } val |= PWR_DEVOFF; #if 0 err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, PWR_P1_SW_EVENTS); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030" "PM_MASTER P1_SW_EVENTS\n", err); return ; } #else while(1) { err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, PWR_P1_SW_EVENTS); mdelay(500); }; #endif return; }
static void board_poweroff(void) { /* int n_usbic_state; */ #if ( defined( CONFIG_MACH_SAMSUNG_P1WIFI ) ) u8 hwsts = 0; u8 vbus_val = 0; twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts, 0x0F /*REG_STS_HW_CONDITIONS*/); if(hwsts & 0x80) // STS_VBUS 0x80 vbus_val = 1; else vbus_val = 0; #endif printk("\nPower off routine - Board Shutdown!! \n"); /* #if defined(CONFIG_USB_ANDROID) android_usb_set_connected(0); #endif */ /* get_real_usbic_state(); */ //gpio_direction_output(GPIO_MSM_RST,0); //gpio_direction_output(GPIO_FONE_ACTIVE, 0); // if (GPIO_TA_CONNECTED_N is LOW) #if ( defined( CONFIG_MACH_SAMSUNG_LATONA ) ) // jypark72, to avoid build error if ( !gpio_get_value( OMAP_GPIO_TA_NCONNECTED ) || gpio_get_value( OMAP_GPIO_JIG_ON18 ) ) #elif ( defined( CONFIG_MACH_SAMSUNG_P1WIFI ) ) if (vbus_val || gpio_get_value( OMAP_GPIO_JIG_ON18 ) ) #endif { printk("Warmreset by TA or USB or Jtag - check 2 pins : JIG_ON18, TA_nConnected \n\n"); preempt_disable(); local_irq_disable(); local_fiq_disable(); #ifdef CONFIG_SAMSUNG_KERNEL_DEBUG omap_writel(0x54455352, OMAP343X_CTRL_BASE + 0x9C4); // set to normal reset #endif #if 1 /* using watchdog reset */ omap_watchdog_reset(); //machine_restart("ta_inserted"); #else /* using core_dpll_warmreset with global reset */ //omap3_configure_core_dpll_warmreset(); machine_restart("ta_inserted"); #endif while(1); } else { while(1) { if (gpio_get_value(OMAP_GPIO_KEY_PWRON)) { printk("Power button is pressed\n\n"); } else { printk("Power Off !\n\n"); gpio_set_value( OMAP_GPIO_PS_HOLD_PU, 0 ); twl4030_poweroff(); //for(;;); } } } return; }
static int pandora_backlight_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; u8 r; if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; if (bl->props.state & BL_CORE_FBBLANK) brightness = 0; if (bl->props.state & BL_CORE_SUSPENDED) brightness = 0; if ((unsigned int)brightness > MAX_USER_VALUE) brightness = MAX_USER_VALUE; if (brightness == 0) { if (bl->props.state & PANDORABL_WAS_OFF) goto done; /* first disable PWM0 output, then clock */ twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1); r &= ~PWM0_ENABLE; twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); r &= ~PWM0_CLK_ENABLE; twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); goto done; } if (bl->props.state & PANDORABL_WAS_OFF) { /* * set PWM duty cycle to max. TPS61161 seems to use this * to calibrate it's PWM sensitivity when it starts. */ twl_i2c_write_u8(TWL_MODULE_PWM, MAX_VALUE, TWL_PWM0_OFF); /* first enable clock, then PWM0 out */ twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1); r &= ~PWM0_ENABLE; r |= PWM0_CLK_ENABLE; twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); r |= PWM0_ENABLE; twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1); /* * TI made it very easy to enable digital control, so easy that * it often triggers unintentionally and disabes PWM control, * so wait until 1 wire mode detection window ends. */ usleep_range(2000, 10000); } twl_i2c_write_u8(TWL_MODULE_PWM, MIN_VALUE + brightness, TWL_PWM0_OFF); done: if (brightness != 0) bl->props.state &= ~PANDORABL_WAS_OFF; else bl->props.state |= PANDORABL_WAS_OFF; return 0; }
int twl6030_vlow_init(int vlow_irq) { int status; u8 val; status = twl_i2c_read_u8(TWL_MODULE_PM_SLAVE_RES, &val, REG_VBATMIN_HI_CFG_STATE); if (status < 0) { pr_err("twl6030: I2C err reading REG_VBATMIN_HI_CFG_STATE: %d\n", status); return status; } status = twl_i2c_write_u8(TWL_MODULE_PM_SLAVE_RES, val | VBATMIN_VLOW_EN, REG_VBATMIN_HI_CFG_STATE); if (status < 0) { pr_err("twl6030: I2C err writing REG_VBATMIN_HI_CFG_STATE: %d\n", status); return status; } status = twl_i2c_read_u8(TWL_MODULE_PIH, &val, REG_INT_MSK_LINE_A); if (status < 0) { pr_err("twl6030: I2C err reading REG_INT_MSK_LINE_A: %d\n", status); return status; } status = twl_i2c_write_u8(TWL_MODULE_PIH, val & ~VLOW_INT_MASK, REG_INT_MSK_LINE_A); if (status < 0) { pr_err("twl6030: I2C err writing REG_INT_MSK_LINE_A: %d\n", status); return status; } #if !defined(CONFIG_LAB126) status = twl_i2c_read_u8(TWL_MODULE_PIH, &val, REG_INT_MSK_STS_A); if (status < 0) { pr_err("twl6030: I2C err reading REG_INT_MSK_STS_A: %d\n", status); return status; } status = twl_i2c_write_u8(TWL_MODULE_PIH, val & ~VLOW_INT_MASK, REG_INT_MSK_STS_A); if (status < 0) { pr_err("twl6030: I2C err writing REG_INT_MSK_STS_A: %d\n", status); return status; } twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &vbatmin_hi_threshold, TWL6030_VBATMIN_HI_THRESHOLD); #else /* Set the desired low battery threshold */ vbatmin_hi_threshold = VBATMIN_HI_THRESHOLD; twl_i2c_write_u8(TWL_MODULE_PM_MASTER, vbatmin_hi_threshold, TWL6030_VBATMIN_HI_THRESHOLD); #endif /* install an irq handler for vlow */ status = request_threaded_irq(vlow_irq, NULL, handle_twl6030_vlow, IRQF_ONESHOT, "TWL6030-VLOW", handle_twl6030_vlow); if (status < 0) { pr_err("twl6030: could not claim vlow irq %d: %d\n", vlow_irq, status); return status; } #if defined(CONFIG_WAKELOCK) wake_lock_init(&vlow_wakelock, WAKE_LOCK_SUSPEND, "low_batt"); #endif return 0; }
static int twl603x_set_offset(struct voltagedomain *vd) { u8 smps_offset_val; int r; /* * In TWL6030 depending on the value of SMPS_OFFSET efuse register * the voltage range supported in standard mode can be either * between 0.6V - 1.3V or 0.7V - 1.4V. * In TWL6030 ES1.0 SMPS_OFFSET efuse is programmed to all 0's where as * starting from TWL6030 ES1.1 the efuse is programmed to 1. * At this point of execution there is no way to identify TWL type, * so use SMPS1/VCORE1 only to identify if SMPS_OFFSET enabled or not * for on both TWL6030/TWL6032 and assume that if SMPS_OFFSET is * enabled for SMPS1/VCORE1 then it's enabled for all SMPS regulators. */ if (SMPS_OFFSET_UNINITIALIZED != smps_offset_state) /* already configured */ return 0; r = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &smps_offset_val, TWL6030_SMPS_OFFSET_REG); if (r) { WARN(1, "%s: No SMPS OFFSET value=??? " \ "read failed %d, max val might be wrong\n", __func__, r); /* Nothing we can do */ return r; } /* Check if SMPS offset already set */ if ((smps_offset_val & TWL603x_SMPS1_OFFSET_EN_MASK) == TWL603x_SMPS1_OFFSET_EN_MASK) { smps_offset_state = SMPS_OFFSET_ENABLED; return 0; } smps_offset_state = SMPS_OFFSET_DISABLED; /* Check if TWL firmware lets us write */ if (!(smps_offset_val & TWL603x_SMPS_OFFSET_RW_ACCESS_MASK)) { WARN(1, "%s: No SMPS OFFSET value=0x%02x " \ "update not possible, max val might be wrong\n", __func__, smps_offset_val); /* Nothing we can do */ return -EACCES; } /* Attempt to set offset for all */ r = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, TWL603x_SMPS_OFFSET_RW_ACCESS_MASK | TWL603x_SMPS_OFFSET_EN_ALL_MASK, TWL6030_SMPS_OFFSET_REG); if (r) { WARN(1, "%s: No SMPS OFFSET value=0x%02x " \ "update failed %d, max val might be wrong\n", __func__, smps_offset_val, r); /* Nothing we can do */ return r; } /* Check if SMPS offset now set */ r = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &smps_offset_val, TWL6030_SMPS_OFFSET_REG); if (r) { WARN(1, "%s: No SMPS OFFSET value=0x%02x " \ "check(r=%d) failed, max val might be wrong\n", __func__, smps_offset_val, r); /* Nothing we can do */ return r; } if (!(smps_offset_val & TWL603x_SMPS1_OFFSET_EN_MASK)) { WARN(1, "%s: No SMPS OFFSET value=0x%02x " \ "check failed (r!=w), max val might be wrong\n", __func__, smps_offset_val); /* Nothing we can do */ return -EFAULT; } smps_offset_state = SMPS_OFFSET_ENABLED; return 0; }
static irqreturn_t charger_ctrl_interrupt(int irq, void *_di) { struct charger_info *di = _di; u8 stat_toggle, stat_reset, stat_set; u8 reg_stat1, reg_hw_cond; int charge_control_state; int ret; ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, ®_stat1, CONTROLLER_STAT1); if (ret) goto i2c_error; ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_hw_cond, STS_HW_CONDITIONS); if (ret) goto i2c_error; charge_control_state = di->charge_control_state; stat_toggle = charge_control_state ^ reg_stat1; stat_set = stat_toggle & reg_stat1; stat_reset = stat_toggle & charge_control_state; dev_dbg(di->dev, "%s: stat_toggle=%02x stat_set=%02x stat_reset=%02x hw_cond=%02x\n", __func__, stat_toggle, stat_set, stat_reset, reg_hw_cond); if (stat_reset & VBUS_DET) { dev_info(di->dev, "VBUS_DET OFF\n"); charger_lock(di); di->vbus_online = 0; di->otg_online = 0; di->invalid_charger = 0; switch_set_state(&di->sdev, 0); charger_unlock(di); charger_update_state(di); } else if (stat_set & VBUS_DET) { dev_info(di->dev, "VBUS_DET ON\n"); charger_lock(di); if (reg_hw_cond & STS_USB_ID) { dev_info(di->dev, "USB_ID ON\n"); di->otg_online = 1; } di->vbus_online = 1; charger_unlock(di); charger_update_state(di); } di->charge_control_state = reg_stat1; return IRQ_HANDLED; i2c_error: dev_err(di->dev, "%s: error while accessing i2c: %d\n", __func__, ret); return IRQ_HANDLED; }
static int __init twl6030_set_offset(struct voltagedomain *voltdm) { /* * In TWL6030 depending on the value of SMPS_OFFSET * efuse register the voltage range supported in * standard mode can be either between 0.6V - 1.3V or * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse * is programmed to all 0's where as starting from * TWL6030 ES1.1 the efuse is programmed to 1 */ if (!is_offset_valid) { int r; r = twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, REG_SMPS_OFFSET); if (r) { pr_err("%s: read of smps offset failed - %d\n", __func__, r); /* Nothing we can do - try later? */ goto out; } /* Check if SMPS offset already set */ if (smps_offset & 0x8) goto out; /* Check if TWL firmware lets us write */ if (!(smps_offset & 0x80)) { WARN(1, "%s: No SMPS OFFSET value=0x%02x" "update not possible, max val might be wrong\n", __func__, smps_offset); /* Nothing we can do */ goto out; } /* Attempt to set offset for all */ r = twl_i2c_write_u8(TWL6030_MODULE_ID0, 0xFF, REG_SMPS_OFFSET); if (r) { WARN(1, "%s: No SMPS OFFSET value=0x%02x" "update failed %d, max val might be wrong\n", __func__, smps_offset, r); /* Nothing we can do */ goto out; } /* Check if SMPS offset now set */ r = twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, REG_SMPS_OFFSET); if (r || !(smps_offset & 0x8)) { WARN(1, "%s: No SMPS OFFSET value=0x%02x" "check(r=%d) failed, max val might be wrong\n", __func__, smps_offset, r); /* Nothing we can do */ goto out; } is_offset_valid = true; } out: /* * even if i2c op failed, there is not much we could have done * Carry on with the hope that we will fix ourselves in next iteration */ return 0; }
int lge_usb_dp_dm_check(struct twl4030_usb *twl) { #if 0 cable_dp_dm_short = 1; return 0; #else int ret; int is_short; u8 reg_val; u8 reg_backup[2]; //20110804 [email protected] [LS855] skipping check d+/d- when detect LT Cable. [START] #if 1 check_cable_type = get_ext_pwr_type(); if( get_external_power_status()||((check_cable_type==LT_CABLE_56K || check_cable_type==LT_CABLE_130K || check_cable_type==LT_CABLE_910K))) return 0; #else if( get_external_power_status()) return 0; #endif //20110804 [email protected] [LS855] skipping check d+/d- when detect LT Cable. [END] #if 1 /* already exist in twl4030_phy_power() */ // printk("twl : 0x%x\n", twl); // regulator_enable(twl->usb3v1); regulator_enable(twl->usb1v8); regulator_enable(twl->usb1v5); /* PHY power up */ twl_i2c_read_u8(TWL4030_MODULE_USB, ®_val, PHY_PWR_CTRL); reg_val &= ~PHY_PWR_PHYPWD; ret = twl_i2c_write_u8(TWL4030_MODULE_USB, reg_val, PHY_PWR_CTRL); if (ret) goto err_short_chk1; /* ULPI register clock gating is enable */ ret = twl_i2c_read_u8(TWL4030_MODULE_USB, ®_backup[0], PHY_CLK_CTRL); if (ret) goto err_short_chk2; ret = twl_i2c_write_u8(TWL4030_MODULE_USB, reg_backup[0] | PHY_CLK_CTRL_CLOCKGATING_EN, PHY_CLK_CTRL); if (ret) goto err_short_chk2; #endif ret = twl_i2c_write_u8(TWL4030_MODULE_USB, FUNC_CTRL_XCVRSELECT_MASK | FUNC_CTRL_OPMODE_MASK, FUNC_CTRL_CLR); if (ret) goto err_short_chk3; /* Disable D+, D- pulldown */ ret = twl_i2c_write_u8(TWL4030_MODULE_USB, OTG_CTRL_DMPULLDOWN | OTG_CTRL_DPPULLDOWN, OTG_CTRL_CLR); if (ret) goto err_short_chk4; /* Set D+ to high, D- to low */ #if 0 ret = twl_i2c_read_u8(TWL4030_MODULE_USB, ®_val, OTHER_FUNC_CTRL); if (ret) goto err_short_chk5; reg_backup[1] = reg_val & ~(DM_PULLUP | DP_PULLUP); ret = twl_i2c_write_u8(TWL4030_MODULE_USB, reg_backup[1] | DP_PULLUP, OTHER_FUNC_CTRL); #else ret = twl_i2c_read_u8(TWL4030_MODULE_USB, ®_backup[1], OTHER_FUNC_CTRL); if (ret) goto err_short_chk5; reg_val = reg_backup[1] & ~(DM_PULLUP | DP_PULLUP); ret = twl_i2c_write_u8(TWL4030_MODULE_USB, reg_val | DP_PULLUP, OTHER_FUNC_CTRL); #endif if (ret) goto err_short_chk5; /* Check D- line */ ret = twl_i2c_read_u8(TWL4030_MODULE_USB, ®_val, OTHER_INT_STS); if (ret) goto err_short_chk6; if ((reg_val & 0x60) == 0x60) is_short = 1; else is_short = 0; /* Set to default */ twl_i2c_write_u8(TWL4030_MODULE_USB, reg_backup[1], OTHER_FUNC_CTRL); twl_i2c_write_u8(TWL4030_MODULE_USB, OTG_CTRL_DMPULLDOWN | OTG_CTRL_DPPULLDOWN, OTG_CTRL_SET); twl_i2c_write_u8(TWL4030_MODULE_USB, FUNC_CTRL_XCVRSELECT_MASK | FUNC_CTRL_OPMODE_MASK, FUNC_CTRL_SET); #if 0 twl_i2c_write_u8(TWL4030_MODULE_USB, reg_backup[0], PHY_CLK_CTRL); /* ULPI register clock gating is disble */ /* LGE_CHANGE_S [VX20000:FW:[email protected]] 2009-06-08, XXX_mbk_ADC_VBATT_THRM * If below code is not present in TA Cable asserted, * we can not set SEL_MADC_MCPC to 1 in ther CARKIT_ANA_CTRL * I don't know why......*/ #if 1 /*#define REG_CARKIT_ANA_CTRL 0xBB */ ret = twl_i2c_read_u8(TWL4030_MODULE_USB, &data_temp, REG_CARKIT_ANA_CTRL); if (ret) { printk(KERN_ERR "%s: BUSY flag.\n", __func__); } #endif /* LGE_CHANGE_E [VX20000:FW:[email protected]] / 2009-06-08 */ #endif twl_i2c_read_u8(TWL4030_MODULE_USB, ®_val, PHY_PWR_CTRL); reg_val |= PHY_PWR_PHYPWD; twl_i2c_write_u8(TWL4030_MODULE_USB, reg_val, PHY_PWR_CTRL); /* PHY power down */ //twl4030_i2c_access(0); regulator_disable(twl->usb1v5); regulator_disable(twl->usb1v8); // regulator_disable(twl->usb3v1); cable_dp_dm_short = is_short; printk(KERN_DEBUG "%s: D+ and D- lines are %s\n", __func__, is_short? "short":"open"); return 0; err_short_chk6: twl_i2c_write_u8(TWL4030_MODULE_USB, reg_backup[1], OTHER_FUNC_CTRL); err_short_chk5: twl_i2c_write_u8(TWL4030_MODULE_USB, OTG_CTRL_DMPULLDOWN | OTG_CTRL_DPPULLDOWN, OTG_CTRL_SET); err_short_chk4: twl_i2c_write_u8(TWL4030_MODULE_USB, FUNC_CTRL_XCVRSELECT_MASK | FUNC_CTRL_OPMODE_MASK, FUNC_CTRL_SET); err_short_chk3: twl_i2c_write_u8(TWL4030_MODULE_USB, reg_backup[0], PHY_CLK_CTRL); err_short_chk2: twl_i2c_write_u8(TWL4030_MODULE_USB, PHY_PWR_PHYPWD, PHY_PWR_CTRL); err_short_chk1: //twl4030_i2c_access(0); regulator_disable(twl->usb1v5); regulator_disable(twl->usb1v8); // regulator_disable(twl->usb3v1); printk(KERN_ERR "%s: Error \n", __func__); return ret; #endif }
void twl4030_poweroff(void) { u8 uninitialized_var(val); int err; u8 pwrana2_val = 0; twl_rewrite_starton_condition(STARTON_CONDITION); // Unlock PROTECT_KEY reg's KEY_TST flag. twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0E, R_PROTECT_KEY); twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xE0, R_PROTECT_KEY); // Get the current PWRANA2 value. twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &pwrana2_val, R_CFG_PWRANA2); // Make LOJIT1_LOWV (bit 2) and LOJIT0_LOWV (bit 1) 0. pwrana2_val &= 0xF9; twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, pwrana2_val, R_CFG_PWRANA2); // Lock back PROTECT_KEY reg's KEY_TST flag. twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xFF, R_PROTECT_KEY); printk(KERN_WARNING "[kernel: twl4030_poweroff] PWRANA2 was set to high jitter mode\n"); #ifdef POWERON_BUGFIX u8 vdd1_type_value, vdd2_type_value, clken_type_value, hfclkout_type_value; // set VDD1_TYPE to TYPE4 vdd1_type_value = 0x04; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, vdd1_type_value, TWL4030_VDD1_TYPE); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_RECEIVER TWL4030_VDD1_TYPE\n", err); return; } // set VDD2_TYPE to TYPE3 vdd2_type_value = 0x03; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, vdd2_type_value, TWL4030_VDD2_TYPE); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_RECEIVER TWL4030_VDD2_TYPE\n", err); return; } // set CLKEN_TYPE to TYPE3 clken_type_value = 0x03; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, clken_type_value, TWL4030_CLKEN_TYPE); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_RECEIVER TWL4030_CLKEN_TYPE\n", err); return; } // set HFCLKOUT_TYPE hfclkout_type_value = 0x00; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, hfclkout_type_value, TWL4030_HFCLKOUT_TYPE); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_RECEIVER TWL4030_HFCLKOUT_TYPE\n", err); return; } #endif /* Make sure SEQ_OFFSYNC is set so that all the res goes to wait-on */ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, CFG_P123_TRANSITION); if (err) { pr_warning("I2C error %d while reading TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err); return; } val |= SEQ_OFFSYNC; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, CFG_P123_TRANSITION); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err); return; } err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, PWR_P1_SW_EVENTS); if (err) { pr_warning("I2C error %d while reading TWL4030 PM_MASTER P1_SW_EVENTS\n", err); return; } val |= PWR_STOPON_POWERON | PWR_DEVOFF; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, PWR_P1_SW_EVENTS); if (err) { pr_warning("I2C error %d while writing TWL4030 PM_MASTER P1_SW_EVENTS\n", err); return; } return; }
static void twl6030_determine_charge_state(struct twl6030_bci_device_info *di) { u8 stat1; int newstate = STATE_BATTERY; /* TODO: i2c error -> fault? */ twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &stat1, CONTROLLER_STAT1); /* TODO: why is STAT1.0 (BAT_TEMP_OVRANGE) always set? */ /* printk("battery: determine_charge_state() stat1=%02x int1=%02x\n", stat1, int1); */ if (stat1 & VBUS_DET) { /* dedicated charger detected by PHY? */ if (di->usb_event == USB_EVENT_CHARGER) newstate = STATE_AC; else newstate = STATE_USB; if (!di->vbus_online) { di->vbus_online = 1; wake_lock(&usb_wake_lock); } } else { /* ensure we don't have a stale USB_EVENT_CHARGER should detect bounce */ di->usb_event = USB_EVENT_NONE; if (di->vbus_online) { di->vbus_online = 0; /* give USB and userspace some time to react before suspending */ wake_lock_timeout(&usb_wake_lock, HZ / 2); } } if (di->state == newstate) return; switch (newstate) { case STATE_FAULT: case STATE_BATTERY: if (is_charging(di)) twl6030_stop_usb_charger(di); break; case STATE_USB: case STATE_AC: /* moving out of STATE_FULL should only happen on unplug * or if we actually run down the battery capacity */ if (di->state == STATE_FULL) { newstate = STATE_FULL; break; } /* TODO: high current? */ if (!is_charging(di)) twl6030_start_usb_charger(di, 500); break; } if (di->state != newstate) { printk("battery: state %s -> %s\n", twl6030_state[di->state], twl6030_state[newstate]); di->state = newstate; power_supply_changed(&di->bat); power_supply_changed(&di->usb); } }
static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) { unsigned long events = 0; int ret = IRQ_NONE; int res; u8 rd_reg; #ifdef WORKQUEUE_RTC static struct work_struct task; #endif #ifdef CONFIG_LOCKDEP /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which * we don't want and can't tolerate. Although it might be * friendlier not to borrow this thread context... */ local_irq_enable(); #endif #ifdef WORKQUEUE_RTC printk("twl_rtc_interrupt rtc "); rtc_ins.rtc =(int)rtc ; INIT_WORK(&task, rtc_interrupt_bottom_half); queue_work(omap_rtc_wq, &task); #endif #ifndef WORKQUEUE_RTC res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (res) goto out; /* * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. * only one (ALARM or RTC) interrupt source may be enabled * at time, we also could check our results * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] */ if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) events |= RTC_IRQF | RTC_AF; else events |= RTC_IRQF | RTC_UF; res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, REG_RTC_STATUS_REG); if (res) goto out; if (twl_class_is_4030()) { /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 * needs 2 reads to clear the interrupt. One read is done in * do_twl_pwrirq(). Doing the second read, to clear * the bit. * * FIXME the reason PWR_ISR1 needs an extra read is that * RTC_IF retriggered until we cleared REG_ALARM_M above. * But re-reading like this is a bad hack; by doing so we * risk wrongly clearing status for some other IRQ (losing * the interrupt). Be smarter about handling RTC_UF ... */ res = twl_i2c_read_u8(TWL4030_MODULE_INT, &rd_reg, TWL4030_INT_PWR_ISR1); if (res) goto out; } /* Notify RTC core on event */ rtc_update_irq(rtc, 1, events); #endif ret = IRQ_HANDLED; out: return ret; }
// 20100920 [email protected] Refine IRQ handlder with a work queue [START_LGE] static void pwrbutton_wq_func(struct work_struct *work){ int err; u8 value; err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); if (!err) { #if 0 // this code is necessary for hdmi sleep sequence. extern int is_hdmi_enabled(void); if(is_hdmi_enabled()) { if(!(value & PWR_PWRON_IRQ)) { input_report_key(pwr, KEY_BACK, 1); input_sync(pwr); input_report_key(pwr, KEY_BACK, 0); input_sync(pwr); extern int WHAT_MODE_IS_IT(void); switch(WHAT_MODE_IS_IT()) // this code is necessary for hdmi sleep sequence from HDMI to LCD in Video mode. { // it takes at least specific time(ms) to change overlay completely. case 0: // Image gallery msleep(1000); break; case 1: // Video mode msleep(4000); break; case 2: // Normal mode break; } input_report_key(pwr, KEY_POWER, 1); input_sync(pwr); input_report_key(pwr, KEY_POWER, 0); input_sync(pwr); msleep(700); } } else { input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); input_sync(pwr); printk( KERN_WARNING "[PWRBUTTON] pwrbutton irq has been processed! %d\n", (value & PWR_PWRON_IRQ)); } #else input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); input_sync(pwr); printk( KERN_WARNING "[PWRBUTTON] pwrbutton irq has been processed! %d\n", (value & PWR_PWRON_IRQ)); #endif } else { dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); printk(KERN_WARNING "[PWRBUTTON] pwrbutton irq caused an error!\n"); } }
int twl6030_vlow_init(int vlow_irq) { int status; u8 val; status = twl_i2c_read_u8(TWL_MODULE_PM_SLAVE_RES, &val, REG_VBATMIN_HI_CFG_STATE); if (status < 0) { pr_err("twl6030: I2C err reading REG_VBATMIN_HI_CFG_STATE: %d\n", status); return status; } status = twl_i2c_write_u8(TWL_MODULE_PM_SLAVE_RES, val | VBATMIN_VLOW_EN, REG_VBATMIN_HI_CFG_STATE); if (status < 0) { pr_err("twl6030: I2C err writing REG_VBATMIN_HI_CFG_STATE: %d\n", status); return status; } status = twl_i2c_read_u8(TWL_MODULE_PIH, &val, REG_INT_MSK_LINE_A); if (status < 0) { pr_err("twl6030: I2C err reading REG_INT_MSK_LINE_A: %d\n", status); return status; } status = twl_i2c_write_u8(TWL_MODULE_PIH, val & ~VLOW_INT_MASK, REG_INT_MSK_LINE_A); if (status < 0) { pr_err("twl6030: I2C err writing REG_INT_MSK_LINE_A: %d\n", status); return status; } status = twl_i2c_read_u8(TWL_MODULE_PIH, &val, REG_INT_MSK_STS_A); if (status < 0) { pr_err("twl6030: I2C err reading REG_INT_MSK_STS_A: %d\n", status); return status; } status = twl_i2c_write_u8(TWL_MODULE_PIH, val & ~VLOW_INT_MASK, REG_INT_MSK_STS_A); if (status < 0) { pr_err("twl6030: I2C err writing REG_INT_MSK_STS_A: %d\n", status); return status; } twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &vbatmin_hi_threshold, TWL6030_VBATMIN_HI_THRESHOLD); /* install an irq handler for vlow */ status = request_threaded_irq(vlow_irq, NULL, handle_twl6030_vlow, IRQF_ONESHOT, "TWL6030-VLOW", handle_twl6030_vlow); if (status < 0) { pr_err("twl6030: could not claim vlow irq %d: %d\n", vlow_irq, status); return status; } return 0; }
/* * Interrupt service routine * * Attends to TWL 6030 power module interruptions events, specifically * USB_PRES (USB charger presence) CHG_PRES (AC charger presence) events * */ static irqreturn_t twl6030charger_ctrl_interrupt(int irq, void *_di) { struct twl6030_bci_device_info *di = _di; int ret; u8 stat_toggle, stat_reset, stat_set = 0; u8 present_charge_state = 0; u8 ac_or_vbus, no_ac_and_vbus; #ifdef CONFIG_LOCKDEP /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which * we don't want and can't tolerate. Although it might be * friendlier not to borrow this thread context... */ local_irq_enable(); #endif /* read charger controller_stat1 */ ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &present_charge_state, CONTROLLER_STAT1); if (ret) return IRQ_NONE; stat_toggle = charge_state ^ present_charge_state; stat_set = stat_toggle & present_charge_state; stat_reset = stat_toggle & charge_state; no_ac_and_vbus = !((present_charge_state) & (VBUS_DET | VAC_DET)); ac_or_vbus = charge_state & (VBUS_DET | VAC_DET); if (no_ac_and_vbus && ac_or_vbus) { pr_debug("No Charging source\n"); /* disable charging when no source present */ } charge_state = present_charge_state; if (stat_reset & VBUS_DET) { pr_debug("usb removed\n"); usb_connected = 0; if (present_charge_state & VAC_DET) twl6030_start_ac_charger(); } if (stat_set & VBUS_DET) { if ((present_charge_state & VAC_DET) && (di->vac_priority)) pr_debug("USB charger detected, continue with VAC\n"); else twl6030_start_usb_charger(); } if (stat_reset & VAC_DET) { pr_debug("vac removed\n"); if (present_charge_state & VBUS_DET) twl6030_start_usb_charger(); } if (stat_set & VAC_DET) { if ((present_charge_state & VBUS_DET) && !(di->vac_priority)) pr_debug("AC charger detected, continue with VBUS\n"); else twl6030_start_ac_charger(); } if (stat_set & CONTROLLER_STAT1_FAULT_WDG) pr_debug("Fault watchdog fired\n"); if (stat_reset & CONTROLLER_STAT1_FAULT_WDG) pr_debug("Fault watchdog recovered\n"); if (stat_set & CONTROLLER_STAT1_BAT_REMOVED) pr_debug("Battery removed\n"); if (stat_reset & CONTROLLER_STAT1_BAT_REMOVED) pr_debug("Battery inserted\n"); if (stat_set & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) pr_debug("Battery temperature overrange\n"); if (stat_reset & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) pr_debug("Battery temperature within range\n"); twl6030_bci_battery_update_status(di); power_supply_changed(&di->bat); return IRQ_HANDLED; }
static irqreturn_t powerbutton_irq(int irq, void *_pwr) { struct input_dev *pwr = _pwr; int err; u8 value; err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,REG_STS_HW_CONDITIONS); if (!err) { char buf[128]; int press = (value & PWR_PWRON_IRQ) ? STATE_RELEASE : STATE_PRESS; char *action = press ? "press" : "release"; input_report_key(pwr, KEY_POWER, press); input_sync(pwr); sprintf(buf, "%s:powi%c:action=%s:", __func__, action[0], action); log_to_metrics(ANDROID_LOG_INFO, "PowerKeyEvent", buf); strcat(buf, "\n"); printk(buf); if(press != prev_press) { if(press) { prev_press = STATE_PRESS; } else { prev_press = STATE_RELEASE; /* Check if we are connected to USB */ if (!twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03) && !(value & (1 << 2))) { /* * No USB, hold a partial wakelock, * scheduled a work 2 seconds later * to switch off the LED */ wake_lock_timeout(&pwrbutton_wakelock, 3*HZ); cancel_delayed_work_sync(&pwrbutton_work); omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); schedule_delayed_work(&pwrbutton_work, HZ*2); } } }else{ if(g_in_suspend==1){ wake_lock(&pwrbutton_wakelock); input_report_key(pwr, KEY_POWER, 1); input_report_key(pwr, KEY_POWER, 0); input_sync(pwr); omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); schedule_delayed_work(&pwrbutton_work, msecs_to_jiffies(2000)); } } } else { dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); /* If an error occurs we don't want to display the SysReq the next time user will * push and release power button. */ prev_press = STATE_UNKNOWN; } return IRQ_HANDLED; }
static int __init twl6030_bci_battery_probe(struct platform_device *pdev) { struct twl6030_bci_platform_data *pdata = pdev->dev.platform_data; struct twl6030_bci_device_info *di; int irq; int ret; u8 rd_reg = 0, controller_stat = 0; di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); ret = -EINVAL; goto err_pdata; } di->dev = &pdev->dev; di->bat.name = "twl6030_bci_battery"; di->bat.supplied_to = twl6030_bci_supplied_to; di->bat.num_supplicants = ARRAY_SIZE(twl6030_bci_supplied_to); di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.properties = twl6030_bci_battery_props; di->bat.num_properties = ARRAY_SIZE(twl6030_bci_battery_props); di->bat.get_property = twl6030_bci_battery_get_property; di->bat.external_power_changed = twl6030_bci_battery_external_power_changed; di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; di->bk_bat.name = "twl6030_bci_bk_battery"; di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bk_bat.properties = twl6030_bk_bci_battery_props; di->bk_bat.num_properties = ARRAY_SIZE(twl6030_bk_bci_battery_props); di->bk_bat.get_property = twl6030_bk_bci_battery_get_property; di->bk_bat.external_power_changed = NULL; /* * Android expects a battery type POWER_SUPPLY_TYPE_USB * as a usb charger battery. This battery * and its "online" property are used to determine if the * usb cable is plugged in or not. */ di->usb_bat.name = "twl6030_bci_usb_battery"; di->usb_bat.supplied_to = twl6030_bci_supplied_to; di->usb_bat.type = POWER_SUPPLY_TYPE_USB; di->usb_bat.properties = twl6030_usb_battery_props; di->usb_bat.num_properties = ARRAY_SIZE(twl6030_usb_battery_props); di->usb_bat.get_property = twl6030_usb_battery_get_property; di->usb_bat.external_power_changed = NULL; di->vac_priority = 1; platform_set_drvdata(pdev, di); /* settings for temperature sensing */ ret = twl6030battery_temp_setup(); if (ret) goto temp_setup_fail; /* request charger fault interruption */ irq = platform_get_irq(pdev, 1); ret = request_irq(irq, twl6030charger_fault_interrupt, 0, "twl_bci_fault", di); if (ret) { dev_dbg(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto batt_irq_fail; } /* request charger ctrl interruption */ irq = platform_get_irq(pdev, 0); ret = request_irq(irq, twl6030charger_ctrl_interrupt, 0, "twl_bci_ctrl", di); if (ret) { dev_dbg(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto chg_irq_fail; } twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_STS_C); ret = power_supply_register(&pdev->dev, &di->bat); if (ret) { dev_dbg(&pdev->dev, "failed to register main battery\n"); goto batt_failed; } INIT_DELAYED_WORK_DEFERRABLE(&di->twl6030_bci_monitor_work, twl6030_bci_battery_work); schedule_delayed_work(&di->twl6030_bci_monitor_work, 0); ret = power_supply_register(&pdev->dev, &di->bk_bat); if (ret) { dev_dbg(&pdev->dev, "failed to register backup battery\n"); goto bk_batt_failed; } ret = power_supply_register(&pdev->dev, &di->usb_bat); if (ret) { dev_dbg(&pdev->dev, "failed to register usb source\n"); goto usb_batt_failed; } INIT_DELAYED_WORK_DEFERRABLE(&di->twl6030_bk_bci_monitor_work, twl6030_bk_bci_battery_work); schedule_delayed_work(&di->twl6030_bk_bci_monitor_work, 500); twl_i2c_read_u8(TWL6030_MODULE_ID0, &rd_reg, REG_MISC1); rd_reg = rd_reg | VAC_MEAS | VBAT_MEAS | BB_MEAS; twl_i2c_write_u8(TWL6030_MODULE_ID0, rd_reg, REG_MISC1); twl_i2c_read_u8(TWL6030_MODULE_ID1, &rd_reg, REG_TOGGLE1); rd_reg = rd_reg | ENABLE_FUELGUAGE; twl_i2c_write_u8(TWL6030_MODULE_ID1, rd_reg, REG_TOGGLE1); twl_i2c_read_u8(TWL_MODULE_MADC, &rd_reg, TWL6030_GPADC_CTRL); rd_reg = rd_reg | ENABLE_ISOURCE; twl_i2c_write_u8(TWL_MODULE_MADC, rd_reg, TWL6030_GPADC_CTRL); twl_i2c_read_u8(TWL_MODULE_USB, &rd_reg, REG_USB_VBUS_CTRL_SET); rd_reg = rd_reg | VBUS_MEAS; twl_i2c_write_u8(TWL_MODULE_USB, rd_reg, REG_USB_VBUS_CTRL_SET); twl_i2c_read_u8(TWL_MODULE_USB, &rd_reg, REG_USB_ID_CTRL_SET); rd_reg = rd_reg | ID_MEAS; twl_i2c_write_u8(TWL_MODULE_USB, rd_reg, REG_USB_ID_CTRL_SET); /* initialize for USB charging */ twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MBAT_TEMP, CONTROLLER_INT_MASK); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MASK_MCHARGERUSB_THMREG, CHARGERUSB_INT_MASK); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_VOREG_4P2, CHARGERUSB_VOREG); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_VICHRG_1500, CHARGERUSB_VICHRG); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_CTRL2_VITERM_100, CHARGERUSB_CTRL2); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_CIN_LIMIT_NONE, CHARGERUSB_CINLIMIT); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_CTRLLIMIT2_1500, CHARGERUSB_CTRLLIMIT2); twl_i2c_write_u8(TWL6030_MODULE_BQ, 0xa0, REG_SAFETY_LIMIT); twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &controller_stat, CONTROLLER_STAT1); if (controller_stat & VBUS_DET) twl6030_start_usb_charger(); if (controller_stat & VAC_DET) twl6030_start_ac_charger(); return 0; usb_batt_failed: power_supply_unregister(&di->bk_bat); bk_batt_failed: power_supply_unregister(&di->bat); batt_failed: free_irq(irq, di); chg_irq_fail: irq = platform_get_irq(pdev, 1); free_irq(irq, NULL); err_pdata: batt_irq_fail: temp_setup_fail: kfree(di); return ret; }
static void twl6030charger_fault_work_handler(struct work_struct *work) { struct charger_device_info *di = container_of(work, struct charger_device_info, twl6030charger_fault_work.work); int charger_fault = 0; int ret; u8 usb_charge_sts = 0, usb_charge_sts1 = 0, usb_charge_sts2 = 0; ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &usb_charge_sts, CHARGERUSB_INT_STATUS); ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &usb_charge_sts1, CHARGERUSB_STATUS_INT1); ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &usb_charge_sts2, CHARGERUSB_STATUS_INT2); di->status_int1 = usb_charge_sts1; di->status_int2 = usb_charge_sts2; if (usb_charge_sts & CURRENT_TERM_INT) dev_dbg(di->dev, "USB CURRENT_TERM_INT\n"); if (usb_charge_sts & CHARGERUSB_THMREG) dev_dbg(di->dev, "USB CHARGERUSB_THMREG\n"); if (usb_charge_sts & CHARGERUSB_FAULT) dev_dbg(di->dev, "USB CHARGERUSB_FAULT\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_TMREG) dev_dbg(di->dev, "USB CHARGER Thermal regulation activated\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_NO_BAT) dev_dbg(di->dev, "No Battery Present\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_BST_OCP) dev_dbg(di->dev, "USB CHARGER Boost Over current protection\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_TH_SHUTD) { // charger_fault = 1; dev_dbg(di->dev, "USB CHARGER Thermal Shutdown\n"); } if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_BAT_OVP) dev_dbg(di->dev, "USB CHARGER Bat Over Voltage Protection\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_POOR_SRC) dev_dbg(di->dev, "USB CHARGER Poor input source\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_SLP_MODE) dev_dbg(di->dev, "USB CHARGER Sleep mode\n"); if (usb_charge_sts1 & CHARGERUSB_STATUS_INT1_VBUS_OVP) dev_dbg(di->dev, "USB CHARGER VBUS over voltage\n"); if (usb_charge_sts2 & CHARGE_DONE) dev_dbg(di->dev, "CHARGE DONE\n"); if (usb_charge_sts2 & CURRENT_TERM){ // change_charge_status(POWER_SUPPLY_STATUS_FULL_END); dev_dbg(di->dev, "[TA] Charge FULL\n"); } if (usb_charge_sts2 & ICCLOOP) dev_dbg(di->dev, "USB ICCLOOP\n"); if (usb_charge_sts2 & ANTICOLLAPSE) dev_dbg(di->dev, "USB ANTICOLLAPSE\n"); if (charger_fault) { change_charge_status(POWER_SUPPLY_STATUS_NOT_CHARGING); dev_err(di->dev, "Charger Fault stop charging\n"); } dev_dbg(di->dev, "Charger fault detected STS, INT1, INT2 %x %x %x\n", usb_charge_sts, usb_charge_sts1, usb_charge_sts2); }
void twl4030_pm_restart(char mode, const char *cmd) { u8 val; int err; int i = 0; #if defined(CONFIG_AP2MODEM_VIATELECOM) extern void ap_poweroff_modem(void); ap_poweroff_modem( ); #endif /* Clear the STARTON_VBAT and STARTON_SWBUG * STARTON_VBAT will cause the auto reboot if battery insert; * STARTON_SWBUG will cause the auto reboot if watchdog has been expired * Mark the STARTON_PWON, which enable switch on transition if power on has been pressed */ twl4030_enable_write(); for(i=0; i<3; i++){ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, PWR_CFG_P1_TRANSITION + i); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030 PM_MASTER PWR_CFG_P%d_TRANSITION\n", err, i+1); goto fail; } val &= (~(STARTON_VBAT)); val |= STARTON_PWON | STARTON_SWBUG |STARTON_RTC | STARTON_CHG; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, PWR_CFG_P1_TRANSITION + i); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030 PM_MASTER PWR_CFG_P%d_TRANSITION\n", err, i+1); goto fail; } } twl4030_disable_write(); err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, SETUP_DONE_BCK, PWR_STS_BOOT); if(err){ printk("I2C error %d while writing TWL4030 PM_MASTER PWR_STS_BOOT\n", err); goto fail; } printk(KERN_WARNING "Restart the system...\n"); /*fire the watchdog*/ val = WATCHDOG_FIRE; err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, WATCHDOG_CFG); if (err) { printk(KERN_WARNING "I2C error %d while writing TWL4030 PM_MASTER PWR_CFG_P%d_TRANSITION\n", err, i+1); goto fail ; } return; fail: printk(KERN_ERR "Fail to restart the system.\n"); while(1) ; }