Exemplo n.º 1
0
/*!
 * @brief Validates that the PPD is a supported device
 *
 * The event handler for this state will be called after a delay to ensure that
 * the output of the USB transceiver has stabilized.  If the D+ line is low, the
 * accessory is a valid phone-powered accessory, so the state is changed to the
 * Connecting State: PPD validate state to identify the accessory.  If the D+ line
 * is high, the accessory is invalid, so the state is changed to the Connected
 * State indicating the invalid accessory.  As a separate verification step, the
 * event handler will also verify that the accessory still appears to be a
 * phone-powered accessory (as opposed to a self-powered accessory).  If the
 * accessory does not appear to be a phone-powered accessory, the state is reset
 * to the Connecting: debounce_dev_type state to attempt to re-debounce the
 * insertion of the accessory.
 *
 * @param polling_interval a return parameter that holds the "polling rate"
 *
 * @return next_state tells the state machine what the next EMU state is
 */
EMU_STATE_T ppd_validate_handler(int *polling_interval)
{
    if (get_device_type() != EMU_DEV_TYPE_PPD)
    {
        tracemsg(_k_d("EMU: ppd_validate_handler: device_type changed! next_state = EMU_STATE_CONNECTING__DEBOUNCE_DEV_TYPE"));
        
        /* Something changed, debounce the device type again */
        *polling_interval = EMU_POLL_CONTINUE;
        
        return EMU_STATE_CONNECTING__DEBOUNCE_DEV_TYPE;
    }

    if (!get_bus_state(EMU_BUS_SIGNAL_DPLUS))
    {
        tracemsg(_k_d("EMU: ppd_validate_handler: D+ is low, next_state = EMU_STATE_CONNECTING__PPD_IDENTIFY"));
        
        /* If D+ is low and the device type has not changed
           go on to the next layer of PPD detection */
        *polling_interval = EMU_POLL_CONTINUE;
        
        return EMU_STATE_CONNECTING__PRE_PPD_IDENTIFY;
    }

    tracemsg(_k_d("EMU: ppd_validate_handler : D+ is high, current_device = MOTO_ACCY_TYPE_INVALID, next_state = EMU_STATE_CONNECTED__INVALID"));
    
    /* D+ is not low at this point so the device is invalid */
    emu_current_device = MOTO_ACCY_TYPE_INVALID;

    *polling_interval = EMU_POLL_CONTINUE;
    
    return EMU_STATE_CONNECTED__INVALID;
}
Exemplo n.º 2
0
/*!
 * @brief ioctl() handler for the charger control interface.
 *
 * This function is the ioctl() interface handler for all charger control operations. It is 
 * not called directly through an ioctl() call on the power IC device, but is executed 
 * from the core ioctl handler for all ioctl requests in the range for charger operations.
 *
 * @param        cmd       ioctl() request received.
 * @param        arg       additional information about request, specific to each request.
 *
 * @return 0 if successful.
 */
int charger_ioctl(unsigned int cmd, unsigned long arg)
{
    int error;
    int temp;     
    tracemsg(_k_d("Charger control ioctl(), request 0x%X (cmd 0x%X)"),(int) cmd, _IOC_NR(cmd));
    
    /* Handle the request. Note that no charger control operations require a structure to be
     * passed - all operations take a single parameter passed by value. */
    switch(cmd)
    {
        case POWER_IC_IOCTL_CHARGER_SET_CHARGE_VOLTAGE:
            return(power_ic_charger_set_charge_voltage((int)arg));
            break;
            

        case POWER_IC_IOCTL_CHARGER_SET_CHARGE_CURRENT:
            return(power_ic_charger_set_charge_current((int)arg));
            break;
            

        case POWER_IC_IOCTL_CHARGER_SET_TRICKLE_CURRENT:
            return(power_ic_charger_set_trickle_current((int)arg));
            break;
            

        case POWER_IC_IOCTL_CHARGER_SET_POWER_PATH:
            return(power_ic_charger_set_power_path((int)arg));
            break;

        case POWER_IC_IOCTL_CHARGER_GET_OVERVOLTAGE:
            /* Read the state of overvoltage from the hardware. */
            if((error = power_ic_charger_get_overvoltage(&temp)))
            {
                return error;
            }
            
            /* Return the read state back to the caller. */
            if(put_user(temp, (int *)arg))
            {
                return -EFAULT;
            }
            break;
            
        case POWER_IC_IOCTL_CHARGER_RESET_OVERVOLTAGE:
            return(power_ic_charger_reset_overvoltage());
            break;

        default: /* This shouldn't be able to happen, but just in case... */
            tracemsg(_k_d("=> 0x%X unsupported charger ioctl command"), (int) cmd);
            return -ENOTTY;
            break;
    
    }
    return 0;
}
Exemplo n.º 3
0
/*!
 * This function is the ioctl() interface handler for all peripheral operations. It is not called
 * directly through an ioctl() call on the power IC device, but is executed from the core ioctl
 * handler for all ioctl requests in the range for peripherals.
 *
 * @param        cmd         the ioctl() command
 * @param        arg         the ioctl() argument
 *
 * @return       This function returns 0 if successful.
 */
int periph_ioctl(unsigned int cmd, unsigned long arg)
{
    int retval = 0;
    int data = (int) arg;
    
    /* Get the actual command from the ioctl request. */
    unsigned int cmd_num = _IOC_NR(cmd);

    tracemsg(_k_d("peripheral ioctl(), request 0x%X (cmd %d)"),(int) cmd, (int)cmd_num);
    
    /* Handle the request. */
    switch(cmd)
    {
        case POWER_IC_IOCTL_PERIPH_SET_BLUETOOTH_ON:
            retval = power_ic_periph_set_bluetooth_on(data);
            break;

        case POWER_IC_IOCTL_PERIPH_SET_FLASH_CARD_ON:
            retval = power_ic_periph_set_flash_card_on(data);
            break;
                
        case POWER_IC_IOCTL_PERIPH_SET_VIBRATOR_LEVEL:
            retval = power_ic_periph_set_vibrator_level(data);
            break;

        case POWER_IC_IOCTL_PERIPH_SET_VIBRATOR_ON:
            retval = power_ic_periph_set_vibrator_on(data);
            break;

        case POWER_IC_IOCTL_PERIPH_SET_WLAN_ON:
            retval = power_ic_periph_set_wlan_on(data);
            break;
	    
        case POWER_IC_IOCTL_PERIPH_SET_WLAN_LOW_POWER_STATE_ON:
            retval = power_ic_periph_set_wlan_low_power_state_on();
            break;
            
        case POWER_IC_IOCTL_PERIPH_SET_CAMERA_ON:
            retval = power_ic_periph_set_camera_on(data);
            break;

        default: /* This shouldn't be able to happen, but just in case... */
            tracemsg(_k_d("=> 0x%X unsupported peripheral ioctl command"), (int) cmd);
            retval = -EINVAL;
            break;
    }

    return retval;
}
Exemplo n.º 4
0
/*!
 * @brief Used to determine what type of PPD this is.
 *
 * The event handler function reads the state of the D+ and D- lines to determine
 * what type of accessory is connected. The state is then changed to the
 * Connected state along with an indication of the identification of the accessory.
 *
 * @param polling_interval a return parameter that holds the "polling rate"
 *
 * @return next_state tells the state machine what the next EMU state is
 */
EMU_STATE_T ppd_identify_handler(int *polling_interval)
{
    *polling_interval = EMU_POLL_CONTINUE;
    
    switch (get_bus_state(EMU_BUS_SIGNAL_DP_DM))
    {
        case EMU_BUS_SIGNAL_STATE_DP_DM_10:
            emu_current_device = MOTO_ACCY_TYPE_HEADSET_EMU_MONO;
            return EMU_STATE_CONNECTED__HEADSET;
            break;
            
        case EMU_BUS_SIGNAL_STATE_DP_DM_00:
            tracemsg(_k_d("The headset is detected as EMU ST headset"));
            emu_current_device = MOTO_ACCY_TYPE_HEADSET_EMU_STEREO;
            return EMU_STATE_CONNECTED__HEADSET;
            break;
            
        case EMU_BUS_SIGNAL_STATE_DP_DM_01:
        case EMU_BUS_SIGNAL_STATE_DP_DM_11:
        default:
            emu_current_device = MOTO_ACCY_TYPE_NOT_SUPPORTED;
            return EMU_STATE_CONNECTED__NOT_SUPPORTED;
            break;
    }
}
Exemplo n.º 5
0
/*!
 * @brief Event handler for the power IC VBUS, SE1, and ID interrupts on SCMA11-Bute platforms
 *
 * This function is the event handler for the power IC VBUS,SE1 and ID interrupts.
 * When the events occur, the job of the interrupt handler is to ensure that
 * the event is reported to the User Space using the poll system call.  
 * This is accomplished through the following mechanism:
 *
 *   - Update the power_ic_event_int variable containing the type of events that
 *     occur before the User Space read it.
 *
 *   - Wake up the power_ic_poll function by updating the power_ic_event_int and
 *     waking up the power_ic_event_int_wait_queue wait queue. 
 *
 * @param event parameter indicating which even occurred
 *
 * @return 1, indicating that the event has been handled
 */
static int emu_glue_int_handler(POWER_IC_EVENT_T event)
{
    tracemsg(_k_d("EMU: emu_glue_int_handler: interrupt received for 0x%x event"),event);

    /* take mutex */
    down(&emu_proc_event_int_mutex);
    
    /* Update power_ic_event_int variable */
    switch (event)
    {
        case POWER_IC_EVENT_ATLAS_USBI: 
            emu_proc_event_int |= POWER_IC_EVENT_INT_VBUS;
            break; 
        case POWER_IC_EVENT_ATLAS_IDI:
            emu_proc_event_int |= POWER_IC_EVENT_INT_ID;
            break; 
        case POWER_IC_EVENT_ATLAS_SE1I:
            emu_proc_event_int |= POWER_IC_EVENT_INT_SE1;
            break;
        default:
            break;
    }
    
    /* Release mutex and wake up poll function */
    emu_proc_event_int_flag = true;
    up(&emu_proc_event_int_mutex);
    wake_up_interruptible(&emu_proc_event_int_wait_queue); 
    return 1;
}
Exemplo n.º 6
0
/*!
 * @brief Enables power to the PPD accessory, then wait for the VBUS line to settle
 *
 * The purpose of this state is to identify the type of phone-powered accessory
 * attached to the phone.  This identification is performed using the following
 * steps:
 *   1.Enable power to the accessory
 *   2.Wait 200 milliseconds.
 *   3.Read the state of the D+ and D- lines.
 * The state of the D+ and D- lines indicates the type of accessory that is
 * connected based on the following table:
 *
 *   D+ D- Accessory       
 *   0  0  Unknown     
 *   0  1  Unknown     
 *   1  0  EMU mono headset    
 *   1  1  Unknown   
 * Table 4: Phone-powered accessory identification
 *
 * The entry function for the state will enable the power to the accessory and
 * configure the timer to expire after 200 milliseconds.  This will cause the
 * event handler function to be called after this delay to check the state of the
 * D+ and D- lines.
 *
 * @param prev_state the previous EMU state
 * @param polling_interval a return parameter that holds the "polling rate"
 */
void pre_ppd_identify_enter(EMU_STATE_T prev_state, int *polling_interval)
{
    tracemsg(_k_d("EMU: pre_ppd_identify_enter: EMU_DEV_TYPE_PPD"));
     /* Power VBUS */
    EMU_SET_REVERSE_MODE(ENABLE);
    
    /* Set timer to wait for D+ and D- lines to stabilize */
    *polling_interval = EMU_POLL_REV_MODE_DELAY;
}
Exemplo n.º 7
0
/*!
 * @brief This utility function sets the audio mode in Atlas and stereo emu headset
 *        pull up.
 *
 * @param mode - The headset mode
 *
 */
void emu_util_set_emu_headset_mode(MOTO_ACCY_HEADSET_MODE_T mode)
{
    switch(mode)
    {   
        case MOTO_ACCY_HEADSET_MODE_NONE:
            EMU_SET_REVERSE_MODE(false);

            /* Don't allow power management to suspend the phone while waiting for VBUS to settle. */
            power_ic_pm_suspend_mask_tbl[POWER_IC_PM_MISC_SLEEPS] |= POWER_IC_EMU_REV_MODE_SLEEP;
            
            /* mdelay must be used here because the delay cannot be allowed to be longer than 20 ms. */
            mdelay(12);
            
            power_ic_pm_suspend_mask_tbl[POWER_IC_PM_MISC_SLEEPS] &= ~(POWER_IC_EMU_REV_MODE_SLEEP);
            
            EMU_SET_EMU_CONN_MODE(POWER_IC_EMU_CONN_MODE_USB);
            EMU_SET_HEADSET_PULL_UP(0);
            /*Following is the work around for the emu headset send/end key*/
            EMU_SET_HS_SEND_END_REGS(1);
            EMU_SET_VUSB_INPUT_SOURCE(EMU_VREG_IN_VINBUS);
            break;
        
        case MOTO_ACCY_HEADSET_MODE_MONO:
            EMU_SET_VUSB_INPUT_SOURCE(EMU_VREG_IN_BPLUS);
            EMU_SET_HS_SEND_END_REGS(0);
            EMU_SET_EMU_CONN_MODE(POWER_IC_EMU_CONN_MODE_MONO_AUDIO);
            EMU_SET_HEADSET_PULL_UP(0);
            
            /* Don't allow power management to suspend the phone while waiting for D- to settle */
            power_ic_pm_suspend_mask_tbl[POWER_IC_PM_MISC_SLEEPS] |= POWER_IC_EMU_DMINUS_MONO_SLEEP;
            msleep(10);
            power_ic_pm_suspend_mask_tbl[POWER_IC_PM_MISC_SLEEPS] &= ~(POWER_IC_EMU_DMINUS_MONO_SLEEP);
            
            EMU_SET_REVERSE_MODE(true);
            break;
            
        case MOTO_ACCY_HEADSET_MODE_STEREO:
            EMU_SET_VUSB_INPUT_SOURCE(EMU_VREG_IN_BPLUS);
            EMU_SET_HS_SEND_END_REGS(0);
            EMU_SET_EMU_CONN_MODE(POWER_IC_EMU_CONN_MODE_STEREO_AUDIO);
            EMU_SET_HEADSET_PULL_UP(1);
            
            /* Don't allow power management to suspend the phone while waiting for D- to settle */
            power_ic_pm_suspend_mask_tbl[POWER_IC_PM_MISC_SLEEPS] |= POWER_IC_EMU_DMINUS_STEREO_SLEEP;
            msleep(10);
            power_ic_pm_suspend_mask_tbl[POWER_IC_PM_MISC_SLEEPS] &= ~(POWER_IC_EMU_DMINUS_STEREO_SLEEP);
            
            EMU_SET_REVERSE_MODE(true);
            break;
        
        default:
            tracemsg(_k_d("EMU: Audio Mode %d not supported"), mode);
    }
}
Exemplo n.º 8
0
/*!
 * @brief Initializes the EMU Glue utils
 *
 * The function performs the initialization of the EMU glue utils variables and register handler
 * to the Power IC EMU related interrupts
 */
int __init emu_glue_utils_init(void)
{
    struct proc_dir_entry * emu_proc;

    tracemsg(_k_d("EMU: emu_glue_utils_init: initializing kernel EMU glue utils"));

    /* configure D+/D- lines and cradle detect line */
    power_ic_gpio_emu_config();

    /* Create emu proc entry */
    emu_proc = create_proc_entry("emu", S_IRUGO | S_IWUGO, NULL);
    if (emu_proc == NULL)
    {
        tracemsg(_k_d(KERN_ERR "Unable to create EMU proc entry in /proc.\n"));
        return -ENOMEM;
    }

    /* Set the proc fops */
    emu_proc->proc_fops = (struct file_operations *)&emu_proc_fops;
 
    /* Initialize variables */ 
    emu_proc_event_int = 0;
    emu_proc_event_int_flag = false;
    power_ic_emu_hw_locked = false;
    emu_proc_opened = false;
    audio_config.headset_mode = MOTO_ACCY_HEADSET_MODE_NONE;
    audio_config.conn_mode = POWER_IC_EMU_CONN_MODE_USB;
    audio_config.id_pull_down = 0;
    
    /* register the light usb driver int */
    power_ic_event_subscribe(EMU_INT_VBUS,usb_detection_int_handler);

    tracemsg(_k_d("USB DET: Start light driver thread"));

    /* Create USB detection thread */
    kernel_thread(usb_detection_state_machine_thread, NULL, 0);

    /* Init ok */
    return 0;
}
Exemplo n.º 9
0
int rtc_ioctl(unsigned int cmd, unsigned long arg)
{
    struct timeval power_ic_time;
    struct timeval * usr_spc_time_val = (struct timeval *)arg;
    int err = 0;

    /* Handle the request. */
    switch(cmd)
    {
        case POWER_IC_IOCTL_GET_TIME:
	    /* Read the TOD and DAY registers and set the data in the timeval
	       structure to the format the Linux uses.*/
	    err = power_ic_rtc_get_time(&power_ic_time);
	    if(copy_to_user(usr_spc_time_val, &power_ic_time, sizeof(power_ic_time)))
	    {
	       err = -EFAULT;
	    }
	    break;
        case POWER_IC_IOCTL_GET_ALARM_TIME:
	    /* Read the TODA and DAYA registers and set the data in the timeval
	       structure to the format the Linux uses.*/
	    err = power_ic_rtc_get_time_alarm(&power_ic_time);
	    if(copy_to_user(usr_spc_time_val, &power_ic_time, sizeof(power_ic_time)))
	    {
	       err = -EFAULT;
	    }
	    break;
        case POWER_IC_IOCTL_SET_TIME:
	    /* Write to  the TOD and DAY registers based on the data in the timeval struct */
	    if(copy_from_user(&power_ic_time,usr_spc_time_val, sizeof(power_ic_time)))
	    {
	       err = -EFAULT;
	    }
	    err = power_ic_rtc_set_time(&power_ic_time);
	    break;	
        case POWER_IC_IOCTL_SET_ALARM_TIME:
	    /* Write to  the TODA and DAYA registers based on the data in the timeval struct */
	    if (copy_from_user(&power_ic_time,usr_spc_time_val,sizeof(power_ic_time)))
	    {
	       err = -EFAULT;
	    }	      
	    err = power_ic_rtc_set_time_alarm(&power_ic_time);
	    break;	
        default: /* This shouldn't be able to happen, but just in case... */
            tracemsg(_k_d("0x%X unsupported ioctl command"), (int) cmd);
            err =  -ENOTTY;
	    break;
    }
    
    return err;
}
Exemplo n.º 10
0
static int emu_proc_open(struct inode *inode, struct file *file)
{
    /* take mutex */
    if(down_interruptible(&emu_proc_opened_mutex))
    {
        tracemsg(_k_d("process received signal while waiting for power ic opened mutex. Exiting."));
        return -EINTR;
    }

    /* Check if the proc is not already open */
    if (emu_proc_opened == true)
    {
        tracemsg(_k_d("/proc/emu control already opened.\n"));

         /* Release mutex */
        up(&emu_proc_opened_mutex);
        return -EBUSY;
    }
    /* Set the opened state */
    emu_proc_opened = true;

    /* MASK VBUS INT */
    power_ic_event_mask(EMU_INT_VBUS);

    /* Unsubsribe usb detection light driver handler on VBUS */
    power_ic_event_unsubscribe(EMU_INT_VBUS,usb_detection_int_handler);

    /* Subscribe to the EMU interrupt events */
    power_ic_event_subscribe(EMU_INT_VBUS, emu_glue_int_handler);
    power_ic_event_subscribe(EMU_INT_ID, emu_glue_int_handler);
    power_ic_event_subscribe(EMU_INT_SE1, emu_glue_int_handler);
    
    /* Release mutex */
    up(&emu_proc_opened_mutex);
    
    return 0;
}
Exemplo n.º 11
0
int power_ic_rtc_set_time(struct timeval *power_ic_time)
{
    int err = 0;
    if (power_ic_time->tv_usec > 500000)
    {
      power_ic_time->tv_sec += 1;
    }
    err = power_ic_set_reg_value(RTC_TOD_REG,POWER_IC_TIME_REG_BIT,
				 power_ic_time->tv_sec % POWER_IC_NUM_SEC_PER_DAY,  POWER_IC_TOD_NUM_BITS );
    err = power_ic_set_reg_value(RTC_DAY_REG,POWER_IC_TIME_REG_BIT,
				 power_ic_time->tv_sec / POWER_IC_NUM_SEC_PER_DAY, POWER_IC_DAY_NUM_BITS);
    tracemsg(_k_d("Set RTC Time \n RTC_TOD = %d \n RTC_DAY = %d \n tv_sec = %d Error = %d \n"),((int)power_ic_time->tv_sec % POWER_IC_NUM_SEC_PER_DAY) , 
	     ((int)power_ic_time->tv_sec / POWER_IC_NUM_SEC_PER_DAY),((int)power_ic_time->tv_sec), err );
    return err;
}
Exemplo n.º 12
0
static int emu_proc_release(struct inode *inode, struct file *file)
{
    /* take mutex */
    if(down_interruptible(&emu_proc_opened_mutex))
    {
        tracemsg(_k_d("process received signal while waiting for power ic opened mutex. Exiting."));
        return -EINTR;
    }

    /* Reset the opened state */
    emu_proc_opened = false;

    /* Release mutex */
    up(&emu_proc_opened_mutex);

    return 0;
}
Exemplo n.º 13
0
int power_ic_rtc_get_time_alarm(struct timeval *power_ic_time)
{
    int toda_reg_val = 0;
    int daya_reg_val = 0;
    int err = 0;
   
    err = power_ic_get_reg_value(RTC_TODA_REG, POWER_IC_TIME_REG_BIT, 
				 &toda_reg_val, POWER_IC_TOD_NUM_BITS);
    err = power_ic_get_reg_value(RTC_DAYA_REG, POWER_IC_TIME_REG_BIT,
				 &daya_reg_val, POWER_IC_DAY_NUM_BITS);

    power_ic_time->tv_sec = toda_reg_val + daya_reg_val * POWER_IC_NUM_SEC_PER_DAY;
    power_ic_time->tv_usec = 0;
 
    tracemsg(_k_d("Get RTC Alarm Time \n RTC_TODA = %d \n RTC_DAYA = %d \n tv_sec = %d Error = %d \n"), toda_reg_val, 
	     daya_reg_val,(int)power_ic_time->tv_sec, err );
    return err;
}
Exemplo n.º 14
0
int power_ic_rtc_set_time_alarm(struct timeval *power_ic_time)
{

    int err = 0;
    
    if (power_ic_time->tv_usec > 500000)
    {
       power_ic_time->tv_sec += 1;
    }
    err = power_ic_set_reg_value(RTC_TODA_REG,POWER_IC_TIME_REG_BIT,
				 power_ic_time->tv_sec % POWER_IC_NUM_SEC_PER_DAY,  POWER_IC_TOD_NUM_BITS );
    err = power_ic_set_reg_value(RTC_DAYA_REG,POWER_IC_TIME_REG_BIT,
				 power_ic_time->tv_sec / POWER_IC_NUM_SEC_PER_DAY, POWER_IC_DAY_NUM_BITS);

    err |= power_ic_event_unmask(RTC_TODA_EVENT);
    
    tracemsg(_k_d("Set RTC Alarm Time \nRTC_TODA = %d \n RTC_DAYA = %d \n tv_sec = %d Error = %d \n"),(int)power_ic_time->tv_sec % POWER_IC_NUM_SEC_PER_DAY , 
	     (int)power_ic_time->tv_sec / POWER_IC_NUM_SEC_PER_DAY,(int)power_ic_time->tv_sec, err );
    return err;
}
Exemplo n.º 15
0
/*!
 * @brief Used to determine what type of PPD this is initially.
 *
 * The event handler function reads the state of the D+ and D- lines to determine
 * what type of accessory is connected. The state is then changed to the
 * Connected state along with an indication of the identification of the accessory.
 *
 * @param polling_interval a return parameter that holds the "polling rate"
 *
 * @return next_state tells the state machine what the next EMU state is
 */
EMU_STATE_T pre_ppd_identify_handler(int *polling_interval)
{
    *polling_interval = EMU_POLL_CONTINUE;
    switch (get_bus_state(EMU_BUS_SIGNAL_DP_DM))
    {
        case EMU_BUS_SIGNAL_STATE_DP_DM_10:   

            tracemsg(_k_d("Set the GPIO for ST headset"));
            EMU_SET_HEADSET_PULL_UP(ENABLE);
            return EMU_STATE_CONNECTING__PPD_IDENTIFY;
            break;
              
        case EMU_BUS_SIGNAL_STATE_DP_DM_00:
        case EMU_BUS_SIGNAL_STATE_DP_DM_01:
        case EMU_BUS_SIGNAL_STATE_DP_DM_11:
        default:
            emu_current_device = MOTO_ACCY_TYPE_NOT_SUPPORTED;
            return EMU_STATE_CONNECTED__NOT_SUPPORTED;
            break;
    }
}
Exemplo n.º 16
0
/*!
 * @brief the read() handler for the EMU power IC proc device node  - for SCMA11 and BUTE platform only.
 *
 * This function implements the read() system call on the power IC device.
 *
 * @param        file        file pointer
 * @param        buf         data
 * @param        count       data size
 * @param        ppos        position unused.
 * 
 *
 * @return 0 if succesful
 */
ssize_t emu_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{   
    int retval = 0;
    /* If there isn't space in the buffer for the results, return a failure. Do not 
     * consider the process complete if this happens as the results are still available. */
    if(count < sizeof(emu_proc_event_int))
    {
        return -EFBIG;
    }
    
    /* take mutex */
    if(down_interruptible(&emu_proc_event_int_mutex))
    {
        tracemsg(_k_d("process received signal while waiting for power ic int event  mutex. Exiting."));
        return -EINTR;
    }
        
    /* Copy the results back to user-space. */
    if( !(copy_to_user((int *)buf, (void *)&emu_proc_event_int, sizeof(emu_proc_event_int))) )
    {
        /* Data was copied successfully. */
        retval = sizeof(emu_proc_event_int);
    }
    else
    {
        /* release mutex */
        up(&emu_proc_event_int_mutex);
        return -EFAULT;
    }
    
    /* Clear variable and release mutex */
    emu_proc_event_int_flag = false;
    emu_proc_event_int = 0;
    up(&emu_proc_event_int_mutex);

    return retval;
}
Exemplo n.º 17
0
/*!
 * @brief Sets the power path.
 *
 * This function configures the path used to supply current from the charger. In
 * dual-path mode, the charger is connected to the phone's supply and can operate
 * the phone without a battery so long as the current drawn isn't too high. In 
 * current-share mode, a battery must be present for the phone to operate.
 *
 * @param        path       New setting for power path.
 *
 * @pre The power path must be set to dual-path prior to enabling the trickle
 * charger.
 *
 * @return returns 0 if successful.
 */
int power_ic_charger_set_power_path(POWER_IC_CHARGER_POWER_PATH_T path)
{
    /* Both FET override and FET control are used to control path. */
    int mask = EMU_FET_OVRD_MASK | EMU_FET_CTRL_MASK;
    int setup;
    
    switch(path)
    {
        /* Hardware-controlled dual-path mode. */
        case POWER_IC_CHARGER_POWER_DUAL_PATH:
            setup = 0;
            break;
        
        /* Hardware-controlled current-share mode. */    
        case POWER_IC_CHARGER_POWER_CURRENT_SHARE:
            setup = EMU_FET_CTRL_MASK;
            break;
                        
        /* Software-overridden dual-path mode. */    
        case POWER_IC_CHARGER_POWER_DUAL_PATH_SW_OVERRIDE:
            setup = EMU_FET_OVRD_MASK;
            break;   
                 
        /* Software-overridden current-share mode. */
        case POWER_IC_CHARGER_POWER_CURRENT_SHARE_SW_OVERRIDE:
            setup = EMU_FET_OVRD_MASK | EMU_FET_CTRL_MASK;
            break;
            
        default:
            tracemsg(_k_d("   power path %d is invalid."), path);
            return -EINVAL;
    }
    
    tracemsg(_k_a("########################## Charger: setting power path 0x%X (masked with 0x%X)"), setup, mask);
    
    return(power_ic_set_reg_mask(POWER_IC_REG_EOC_POWER_CONTROL_0, mask, setup));
}
Exemplo n.º 18
0
/*!
 * @brief Sets the charge voltage.
 *
 * This function sets the maximum voltage that the battery will charged up to.
 *
 * @param        charge_voltage       Maximum charge voltage to be set.
 *
 * @return returns 0 if successful.
 */
int power_ic_charger_set_charge_voltage(int charge_voltage)
{   
    tracemsg(_k_d("Charger: setting VCHRG 0x%X"), charge_voltage);
    return(power_ic_set_reg_mask(POWER_IC_REG_EOC_POWER_CONTROL_0, EMU_VCHRG_MASK, charge_voltage));
}
Exemplo n.º 19
0
static int emu_proc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned int ret_val = 0;
    
    POWER_IC_EMU_GLUE_READ_SENSE_T read_sense; 
    POWER_IC_EMU_GLUE_TRANSCEIVER_PARAMS_T trans_params;
    POWER_IC_FET_CONTROL_T fet_ctrl;

    /* prev lockout status */
    static bool prev_emu_hw_lockout_state = false;

    /* what devices were connected before lockout */
    static MOTO_ACCY_MASK_T connected_device_before_lock = 0;
    MOTO_ACCY_MASK_T connected_device;
    
    /* Get the actual command from the ioctl request. */
    unsigned int cmd_num = _IOC_NR(cmd);
    
    if ((cmd_num >= POWER_IC_IOC_CMD_EMU_GLUE_BASE) && (cmd_num <= POWER_IC_IOC_CMD_EMU_GLUE_LAST_CMD))
    { 
        tracemsg(_k_d("EMU GLUE control ioctl(), request 0x%X (cmd 0x%X)"),(int) cmd, _IOC_NR(cmd));

        /* Handle the request. */
        switch(cmd)
        {
            case POWER_IC_IOCTL_CMD_EMU_GLUE_READ_SENSE:
                /* Fetch the data passed from user space. */
                if(copy_from_user((void *)&read_sense, (void *)arg, sizeof(read_sense)) != 0)
                {
                    tracemsg(_k_d("error copying data from user space."));
                    ret_val = -EFAULT;
                }  
                else
                {
                    /* Read the sense and clear the interrupt if requested */
                    read_sense.sense = emu_glue_read_sense(read_sense.clear_int_flags);

                    /* Only the sense value read needs to be sent back to the caller. */
                    if(put_user(read_sense.sense,&(((POWER_IC_EMU_GLUE_READ_SENSE_T *)arg)->sense)) != 0)
                    {
                        tracemsg(_k_d("error copying read bits to user space."));
                        ret_val = -EFAULT;
                    }
                }
                break;
                
            case POWER_IC_IOCTL_CMD_EMU_GLUE_LOCKOUT_CHANGES:
                power_ic_emu_hw_locked = (bool)(arg == 0 ? 0 : 1);
                 
                if (power_ic_emu_hw_locked)
                {
                    /* Make sure the hardware is not already locked */
                    if (prev_emu_hw_lockout_state == false)
                    {
                        /* If the EMU hardware needs to be locked, keep track of
                           the currently connected accessory */
                        connected_device_before_lock = moto_accy_get_all_devices();
                    }
                }
                else
                {                   
                    /* If the EMU hardware was previously locked but is now unlocked the accessory may need
                       to be reconfigured. */
                    if (prev_emu_hw_lockout_state == true)
                    {
                        connected_device = moto_accy_get_all_devices();
                        
                        if (connected_device_before_lock == connected_device)
                        {
                            if ((ACCY_BITMASK_ISSET(connected_device, MOTO_ACCY_TYPE_HEADSET_EMU_MONO)) ||
                                (ACCY_BITMASK_ISSET(connected_device, MOTO_ACCY_TYPE_HEADSET_EMU_STEREO)))
                            {
                                audio_config.id_pull_down = 0;
                                audio_config.conn_mode = 0;
                                emu_util_set_emu_headset_mode(audio_config.headset_mode);
                            }
                            else if ((ACCY_BITMASK_ISSET(connected_device, MOTO_ACCY_TYPE_CARKIT_MID)) ||
                                     (ACCY_BITMASK_ISSET(connected_device, MOTO_ACCY_TYPE_CARKIT_FAST)))
                            {
                                audio_config.headset_mode = MOTO_ACCY_HEADSET_MODE_NONE;
                                EMU_SET_EMU_CONN_MODE(audio_config.conn_mode);
                                EMU_SET_ID_PULL_DOWN(audio_config.id_pull_down);
                            }
                            else
                            {
                                audio_config.headset_mode = MOTO_ACCY_HEADSET_MODE_NONE;
                                audio_config.conn_mode = POWER_IC_EMU_CONN_MODE_USB;
                                audio_config.id_pull_down = 0;  
                            }
                        }
                        else
                        {
                            audio_config.headset_mode = MOTO_ACCY_HEADSET_MODE_NONE;
                            audio_config.conn_mode = POWER_IC_EMU_CONN_MODE_USB;
                            audio_config.id_pull_down = 0;  
                        }
                    }
                }

                prev_emu_hw_lockout_state = power_ic_emu_hw_locked;
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_GET_FET_CONTROL:
                if ((power_ic_get_reg_value(POWER_IC_REG_ATLAS_CHARGER_0, 10, (int *)&(fet_ctrl), 2)) != 0)
                {
                    ret_val = -EIO;
                }
                /* Only the sense value read needs to be sent back to the caller. */
                else if(put_user(fet_ctrl, (((int *)arg))) != 0)
                {
                    tracemsg(_k_d("error copying read bits to user space."));
                    ret_val = -EFAULT;
                }
                break;
                   
            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_FET_CONTROL:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_CHARGER_0, 10,
                                       arg, 2);
                break;
                
            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_VBUS_5K_PD:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_CHARGER_0, 19,
                                       (arg == 0 ? 0 : 1), 1);
                break;
         
            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_VBUS_70K_PD:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 6,
                                       (arg == 0 ? 0 : 1), 1);
                               
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_REVERSE_MODE:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_CHARGE_USB_1, 5,
                                   (arg == 0 ? 0 : 1), 1);
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_ID_PU:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 22,
                                       (arg == 0 ? 0 : 1), 1);
                break;            
         
            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_ID_PD:
                 power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 20,
                                       (arg == 0 ? 0 : 1), 1);
                 break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_ID_STEREO_PU:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_CHARGE_USB_1, 8,
                                       (arg == 0 ? 0 : 1), 1);
                break;  

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_CONN_MODE:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 14,
                                       arg, 3);
                break;  

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_DPLUS_150K_PU:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 5,
                                       (arg == 0 ? 0 : 1), 1);            
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_DPLUS_1_5K_PU:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 2,
                                       (arg == 0 ? 0 : 1), 1); 
                break;
  
            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_LOW_SPEED_MODE:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 0,
                                       (arg == 0 ? 0 : 1), 1);    
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_USB_SUSPEND:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_USB_0, 1,
                                       (arg == 0 ? 0 : 1), 1);    
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_TRANSCEIVER_PARAMS:
                /* Fetch the data passed from user space. */
                if(copy_from_user((void *)&trans_params, (void *)arg, sizeof(trans_params)) != 0)
                {
                    tracemsg(_k_d("error copying data from user space."));
                    ret_val = -EFAULT;
                }
                else
                {
                    /* Call local function */
                    emu_glue_set_transceiver_params(trans_params);
                }
                break;

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_ID_INT_MASK:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_INT_MASK_0, 19,
                                       arg, 1);    
                break;  

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_VBUS_INT_MASK:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_INT_MASK_0, 16,
                                       arg, 1);    
                break; 

            case POWER_IC_IOCTL_CMD_EMU_GLUE_SET_SE1_INT_MASK:
                power_ic_set_reg_value(POWER_IC_REG_ATLAS_INT_MASK_0, 21,
                                       arg, 1);    
                break;

            default: /* This shouldn't be able to happen, but just in case... */
                tracemsg(_k_d("=> 0x%X unsupported emu proc ioctl command"), (int) cmd);
                ret_val = -ENOTTY;
                break;
        }
    }
    else /* The driver doesn't support this request. */
    {
        tracemsg(_k_d("0x%X unsupported ioctl command"), (int) cmd);
        ret_val = -ENOTTY;
    }
        
    return ret_val;
}
Exemplo n.º 20
0
/*!
 * @brief Used to debounce the device type
 *
 * The debouncing of the accessory is done using the base accessory type
 * (self-powered versus phone-powered).  The purpose of the event handler is to
 * wait until the base accessory type has stabilized before continuing with
 * accessory identification.  This is accomplished by having the event handler
 * execute every 100 milliseconds until the base accessory type has not changed
 * for 300 milliseconds.
 * Once the debounce is complete, the event handler will perform the initial
 * accessory identification and transition to the appropriate next state.
 * 
 * @param polling_interval a return parameter that points to the "polling rate"
 *
 * @return next_state tells the state machine what the next EMU state is
 */
EMU_STATE_T debounce_dev_type_handler(int *polling_interval)
{
    EMU_ID_RESISTOR_T id_res;
    EMU_DEV_TYPE_T device_type;
    EMU_STATE_T next_state;
    
    /* Debounce the device type */
    if ((is_device_type_debounced(&device_type)) == FALSE)
    {
        /* Come back to this state after polling interval expires */
        *polling_interval = EMU_POLL_DFLT_DEB_DELAY;
        
        return EMU_STATE_CONNECTING__DEBOUNCE_DEV_TYPE;      
    }

    /* Finished debouncing, reset the counter */
    emu_debounce_counter = 0;
    
    /* Store the device type */
    emu_current_device_type = device_type;
    
    /* Now that the device type is debounced... */
    switch (device_type)
    {
        case EMU_DEV_TYPE_PPD:
            tracemsg(_k_d("EMU: debounce_dev_type_handler: EMU_DEV_TYPE_PPD"));
            
            /* Verify that ID res is 100k */
            if (get_id_res_value() != EMU_ID_RESISTOR_100K)
            {                
                /*if ID is not 100k, the accy is invalid */
                emu_current_device = MOTO_ACCY_TYPE_INVALID;
                next_state =  EMU_STATE_CONNECTED__INVALID;
                tracemsg(_k_d("EMU: debounce_dev_type_handler: ID != 100k"));
            }
            else
            {
                /* Go to the first PPD polling state */
                next_state = EMU_STATE_CONNECTING__PPD_VALIDATE;
            }
            break;
            
        case EMU_DEV_TYPE_SPD:
            tracemsg(_k_d("EMU: debounce_dev_type_handler: EMU_DEV_TYPE_SPD"));
            
            /* Get the resistance on ID */
            id_res = get_id_res_value();
            
            /* Is the device single ended one */
            if (get_bus_state(EMU_BUS_SIGNAL_SE1))
            {
                id_res += EMU_ID_RESISTOR_SE1;
            }

            emu_current_device = spd_id_translation_table[id_res].device;
            next_state = spd_id_translation_table[id_res].next_state;

            /* If we were previously in the unpowered SIHF state, and the
               device is still not behaving (looks like an unpowered sihf),
               set the device as invalid and transition to the connected state */
            if ((emu_prev_state == EMU_STATE_CONNECTING__UNPOWERED_SIHF) &&
                (next_state == EMU_STATE_CONNECTING__UNPOWERED_SIHF))
            {
                emu_current_device = MOTO_ACCY_TYPE_INVALID;
                next_state = EMU_STATE_CONNECTED__INVALID;
            }
            break;
            
        case EMU_DEV_TYPE_NOT_SUPPORTED:
            tracemsg(_k_d("EMU: debounce_dev_type_handler: EMU_DEV_TYPE_NOT_SUPPORTED"));
            
            emu_current_device = MOTO_ACCY_TYPE_NOT_SUPPORTED;
            next_state = EMU_STATE_CONNECTED__NOT_SUPPORTED;
            break;
            
        case EMU_DEV_TYPE_INVALID:
            tracemsg(_k_d("EMU: debounce_dev_type_handler: EMU_DEV_TYPE_INVALID"));
                
            emu_current_device = MOTO_ACCY_TYPE_INVALID;
            next_state = EMU_STATE_CONNECTED__INVALID;
            break;
            
        case EMU_DEV_TYPE_NONE:
            tracemsg(_k_d("EMU: debounce_dev_type_handler: EMU_DEV_TYPE_NONE"));
        default:
            emu_current_device = MOTO_ACCY_TYPE_NONE;
            next_state = EMU_STATE_DISCONNECTED;
            break;
    }

    tracemsg(_k_d("EMU: debounce_dev_type_handler: current_device = %d, next_state = %d"),
             emu_current_device, next_state);

    *polling_interval = EMU_POLL_CONTINUE;
    
    return next_state;
}
Exemplo n.º 21
0
/*!
 * @brief Connecting State: spd_delay_handler function
 *
 * The event handler for this state will only be called after the 5 millisecond
 * delay and is responsible for checking the state of the D- line.
 *
 * @param polling_interval a return parameter that holds the "polling rate"
 *
 * @return next_state tells the state machine what the next EMU state is
 */
EMU_STATE_T spd_delay_handler(int *polling_interval)
{
    int vbus;
    EMU_STATE_T next_state = EMU_STATE_CONNECTED__POLL_SPD_REMOVAL;
        
    /* Verify that the device type didn't change while polling */
    if (get_device_type() != EMU_DEV_TYPE_SPD)
    {
        tracemsg(_k_d("EMU: spd_delay_handler:device type changed while polling!"));

        *polling_interval = EMU_POLL_CONTINUE;
        
        /* Something changed debounce the accy again */
        return EMU_STATE_CONNECTING__DEBOUNCE_DEV_TYPE;
    }
    
    /* If dminus is high then this charger is a SIHF */
    if (get_bus_state(EMU_BUS_SIGNAL_DMINUS))
    {
        if (emu_current_device == MOTO_ACCY_TYPE_CHARGER_FAST)
        {
            emu_current_device = MOTO_ACCY_TYPE_CARKIT_FAST;
        }
        else
        {
            emu_current_device = MOTO_ACCY_TYPE_CARKIT_MID;
        }
    }
    else
    {
        if (emu_current_device == MOTO_ACCY_TYPE_CHARGER_FAST)
        {
            /* Convert the Batt+ channel to get the VBUS voltage */
            if (power_ic_atod_single_channel(EMU_A2D_VBUS, &vbus) != 0)
            {
                vbus = 0;
            }
            
            if (vbus >= EMU_VBUS_5VOLTS)
            {
                /*current_device is already set correctly */
                /*current_device = MOTO_ACCY_TYPE_CHARGER_FAST;*/
            }
            else if (vbus >= EMU_VBUS_4_5VOLTS)
            {
                emu_current_device = MOTO_ACCY_TYPE_CHARGER_FAST_3G;
            }
            else /*if (vbus < VBUS_4_5VOLTS)*/
            {
                emu_current_device = MOTO_ACCY_TYPE_INVALID;
                next_state = EMU_STATE_CONNECTED__INVALID;
            }
        }
        /*else if (emu_current_device == MOTO_ACCY_TYPE_CHARGER_MID) */
        /* Nothing to do here for Mid rate chargers */
    }

    tracemsg(_k_d("EMU: current_device = %d"),
             emu_current_device);

    *polling_interval = EMU_POLL_CONTINUE;
    
    /* Go to the determined connected substate */
    return next_state;
}