/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Copyright (C) 2009 by Rob Purchase
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "pcf50635.h"
#include "i2c.h"
#include "system.h"

#define PCF50635_ADDR 0xe6

int pcf50635_write(int address, unsigned char val)
{
    unsigned char data[] = { address, val };
    return i2c_write(PCF50635_ADDR, data, 2);
}

int pcf50635_write_multiple(int address, const unsigned char* buf, int count)
{
    int i;

    for (i = 0; i < count; i++)
        pcf50635_write(address + i, buf[i]);

    return 0;
}

int pcf50635_read(int address)
{
    unsigned char val = -1;
    i2c_readmem(PCF50635_ADDR, address, &val, 1);
    return val;
}

int pcf50635_read_multiple(int address, unsigned char* buf, int count)
{
    return i2c_readmem(PCF50635_ADDR, address, buf, count);
}

void pcf50635_init(void)
{
#ifdef COWON_D2
    static const char init_data[] = 
    {
        /* DOWN1: 1.2V, max DVM step, enabled */
        PCF5063X_REG_DOWN1OUT, 0x13,
        PCF5063X_REG_DOWN1CTL, 0x1e,
        PCF5063X_REG_DOWN1ENA, 0x1,

        /* DOWN2: 1.8V, max DVM step, enabled */
        PCF5063X_REG_DOWN2OUT, 0x2f,  
        PCF5063X_REG_DOWN2CTL, 0x1e,
        PCF5063X_REG_DOWN2ENA, 0x1,
        
        /* AUTO: 3.0V, enabled */
        PCF5063X_REG_AUTOOUT,  0x5f,
        PCF5063X_REG_AUTOENA,  0x1,
        
        /* LDO1: 3.3V, enabled */
        PCF5063X_REG_LDO1OUT,  0x18,
        PCF5063X_REG_LDO1ENA,  0x1,
        
        /* LDO2: 3.0V, enabled */
        PCF5063X_REG_LDO2OUT,  0x15,
        PCF5063X_REG_LDO2ENA,  0x1,
        
        /* LDO4: 3.0V, enabled */
        PCF5063X_REG_LDO4OUT,  0x15,
        PCF5063X_REG_LDO4ENA,  0x1,
        
        /* LDO5: 1.8V, enabled */
        PCF5063X_REG_LDO5OUT,  0x9,
        PCF5063X_REG_LDO5ENA,  0x1,
        
        /* LDO6: 2.1V, enabled */
        PCF5063X_REG_LDO6OUT,  0xc,
        PCF5063X_REG_LDO6ENA,  0x1,
        
        /* LDO3 and HCLDO disabled */
        PCF5063X_REG_LDO3ENA,  0x0,
        PCF5063X_REG_HCLDOENA, 0x0,
        
        /* Disable GPIOs */
        PCF5063X_REG_GPIOCTL,  0x0,
        PCF5063X_REG_GPIO1CFG, 0x0,
        PCF5063X_REG_GPIO2CFG, 0x0,
        PCF5063X_REG_GPIO3CFG, 0x0,
        
        /* IRQ masks (OF values in brackets) */
        PCF5063X_REG_INT1M,    0xfa, /* (0x8a enable alarm, usbins, adpins) */
        PCF5063X_REG_INT2M,    0xff, /* (0xff all masked) */
        PCF5063X_REG_INT3M,    0x7f, /* (0x7f enable onkey1s) */
        PCF5063X_REG_INT4M,    0xff, /* (0xfd enable lowbat) */
        PCF5063X_REG_INT5M,    0xff, /* (0xff all masked) */
        
        /* Wakeup mode */
        PCF5063X_REG_OOCMODE,  0x0,  /* onkey falling edge */
        PCF5063X_REG_OOCCTL,   0x2,  /* actphrst = phase 3 */
        PCF5063X_REG_OOCWAKE,  0xc1, /* wakeup on adapter, usb, onkey */
        
        /* Configure battery charger as per OF */
        PCF5063X_REG_MBCC2,    0xa8, /* Vmax = 4.2V, Vbatcond = 2.7V, long debounce */
        PCF5063X_REG_MBCC3,    0x2a, /* precharge level = 16% */
        PCF5063X_REG_MBCC4,    0x94, /* fastcharge level = 58% */
        PCF5063X_REG_MBCC5,    0xff, /* fastcharge level (usb) = 100%  */
        PCF5063X_REG_MBCC6,    0x4,  /* cutoff level = 12.5% */
        PCF5063X_REG_MBCC7,    0xc1, /* bat-sysImax = 2.2A, USB = 500mA */
        PCF5063X_REG_BVMCTL,   0xe,  /* batok level = 3.4V */

        /* end marker */
        0};

    const char* ptr;
    for (ptr = init_data; *ptr != 0; ptr += 2)
        pcf50635_write(ptr[0], ptr[1]);

    /* Enable automatic charging, preserving default values */
    pcf50635_write(PCF5063X_REG_MBCC1,
        pcf50635_read(PCF5063X_REG_MBCC1) | 7);
    
#endif
}

void pcf50635_read_adc(int adc, short* res1, short* res2)
{
    int adcs1 = 0, adcs2 = 0, adcs3 = 0;

    int level = disable_irq_save();

    pcf50635_write(PCF5063X_REG_ADCC1, PCF5063X_ADCC1_ADCSTART | adc);

    do {
        adcs3 = pcf50635_read(PCF5063X_REG_ADCS3);
    } while (!(adcs3 & PCF5063X_ADCS3_ADCRDY));

    if (res1 != NULL) adcs1 = pcf50635_read(PCF5063X_REG_ADCS1);
    if (res2 != NULL) adcs2 = pcf50635_read(PCF5063X_REG_ADCS2);

    pcf50635_write(PCF5063X_REG_ADCC1, 0);

    restore_interrupt(level);

    if (res1 != NULL) *res1 = (adcs1 << 2) | (adcs3 & 3);
    if (res2 != NULL) *res2 = (adcs2 << 2) | ((adcs3 & 0xC) >> 2);
}
