static void menelaus_write()

in hw/rtc/twl92230.c [401:702]


static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
{
    MenelausState *s = (MenelausState *) opaque;
    int line;
    struct tm tm;

    switch (addr) {
    case MENELAUS_VCORE_CTRL1:
        s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
        break;
    case MENELAUS_VCORE_CTRL2:
        s->vcore[1] = value;
        break;
    case MENELAUS_VCORE_CTRL3:
        s->vcore[2] = MIN(value & 0x1f, 0x12);
        break;
    case MENELAUS_VCORE_CTRL4:
        s->vcore[3] = MIN(value & 0x1f, 0x12);
        break;
    case MENELAUS_VCORE_CTRL5:
        s->vcore[4] = value & 3;
        /* XXX
         * auto set to 3 on M_Active, nRESWARM
         * auto set to 0 on M_WaitOn, M_Backup
         */
        break;

    case MENELAUS_DCDC_CTRL1:
        s->dcdc[0] = value & 0x3f;
        break;
    case MENELAUS_DCDC_CTRL2:
        s->dcdc[1] = value & 0x07;
        /* XXX
         * auto set to 3 on M_Active, nRESWARM
         * auto set to 0 on M_WaitOn, M_Backup
         */
        break;
    case MENELAUS_DCDC_CTRL3:
        s->dcdc[2] = value & 0x07;
        break;

    case MENELAUS_LDO_CTRL1:
        s->ldo[0] = value;
        break;
    case MENELAUS_LDO_CTRL2:
        s->ldo[1] = value & 0x7f;
        /* XXX
         * auto set to 0x7e on M_WaitOn, M_Backup
         */
        break;
    case MENELAUS_LDO_CTRL3:
        s->ldo[2] = value & 3;
        /* XXX
         * auto set to 3 on M_Active, nRESWARM
         * auto set to 0 on M_WaitOn, M_Backup
         */
        break;
    case MENELAUS_LDO_CTRL4:
        s->ldo[3] = value & 3;
        /* XXX
         * auto set to 3 on M_Active, nRESWARM
         * auto set to 0 on M_WaitOn, M_Backup
         */
        break;
    case MENELAUS_LDO_CTRL5:
        s->ldo[4] = value & 3;
        /* XXX
         * auto set to 3 on M_Active, nRESWARM
         * auto set to 0 on M_WaitOn, M_Backup
         */
        break;
    case MENELAUS_LDO_CTRL6:
        s->ldo[5] = value & 3;
        break;
    case MENELAUS_LDO_CTRL7:
        s->ldo[6] = value & 3;
        break;
    case MENELAUS_LDO_CTRL8:
        s->ldo[7] = value & 3;
        break;

    case MENELAUS_SLEEP_CTRL1:
    case MENELAUS_SLEEP_CTRL2:
        s->sleep[addr - MENELAUS_SLEEP_CTRL1] = value;
        break;

    case MENELAUS_DEVICE_OFF:
        if (value & 1) {
            menelaus_reset(I2C_SLAVE(s));
        }
        break;

    case MENELAUS_OSC_CTRL:
        s->osc = value & 7;
        break;

    case MENELAUS_DETECT_CTRL:
        s->detect = value & 0x7f;
        break;

    case MENELAUS_INT_MASK1:
        s->mask &= 0xf00;
        s->mask |= value << 0;
        menelaus_update(s);
        break;
    case MENELAUS_INT_MASK2:
        s->mask &= 0x0ff;
        s->mask |= value << 8;
        menelaus_update(s);
        break;

    case MENELAUS_INT_ACK1:
        s->status &= ~(((uint16_t) value) << 0);
        menelaus_update(s);
        break;
    case MENELAUS_INT_ACK2:
        s->status &= ~(((uint16_t) value) << 8);
        menelaus_update(s);
        break;

    case MENELAUS_GPIO_CTRL:
        for (line = 0; line < 3; line ++) {
            if (((s->dir ^ value) >> line) & 1) {
                qemu_set_irq(s->out[line],
                             ((s->outputs & ~s->dir) >> line) & 1);
            }
        }
        s->dir = value & 0x67;
        break;
    case MENELAUS_GPIO_OUT:
        for (line = 0; line < 3; line ++) {
            if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
                qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
            }
        }
        s->outputs = value & 0x07;
        break;

    case MENELAUS_BBSMS:
        s->bbsms = 0x0d;
        break;

    case MENELAUS_RTC_CTRL:
        if ((s->rtc.ctrl ^ value) & 1) {			/* RTC_EN */
            if (value & 1)
                menelaus_rtc_start(s);
            else
                menelaus_rtc_stop(s);
        }
        s->rtc.ctrl = value & 0x1f;
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_UPDATE:
        menelaus_rtc_update(s);
        memcpy(&tm, &s->rtc.tm, sizeof(tm));
        switch (value & 0xf) {
        case 0:
            break;
        case 1:
            tm.tm_sec = s->rtc.new.tm_sec;
            break;
        case 2:
            tm.tm_min = s->rtc.new.tm_min;
            break;
        case 3:
            if (s->rtc.new.tm_hour > 23)
                goto rtc_badness;
            tm.tm_hour = s->rtc.new.tm_hour;
            break;
        case 4:
            if (s->rtc.new.tm_mday < 1)
                goto rtc_badness;
            /* TODO check range */
            tm.tm_mday = s->rtc.new.tm_mday;
            break;
        case 5:
            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
                goto rtc_badness;
            tm.tm_mon = s->rtc.new.tm_mon;
            break;
        case 6:
            tm.tm_year = s->rtc.new.tm_year;
            break;
        case 7:
            /* TODO set .tm_mday instead */
            tm.tm_wday = s->rtc.new.tm_wday;
            break;
        case 8:
            if (s->rtc.new.tm_hour > 23)
                goto rtc_badness;
            if (s->rtc.new.tm_mday < 1)
                goto rtc_badness;
            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
                goto rtc_badness;
            tm.tm_sec = s->rtc.new.tm_sec;
            tm.tm_min = s->rtc.new.tm_min;
            tm.tm_hour = s->rtc.new.tm_hour;
            tm.tm_mday = s->rtc.new.tm_mday;
            tm.tm_mon = s->rtc.new.tm_mon;
            tm.tm_year = s->rtc.new.tm_year;
            break;
        rtc_badness:
        default:
            fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
                            __func__, value);
            s->status |= 1 << 10;				/* RTCERR */
            menelaus_update(s);
        }
        s->rtc.sec_offset = qemu_timedate_diff(&tm);
        break;
    case MENELAUS_RTC_SEC:
        s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
        break;
    case MENELAUS_RTC_MIN:
        s->rtc.tm.tm_min = from_bcd(value & 0x7f);
        break;
    case MENELAUS_RTC_HR:
        s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ?	/* MODE12_n24 */
                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
                from_bcd(value & 0x3f);
        break;
    case MENELAUS_RTC_DAY:
        s->rtc.tm.tm_mday = from_bcd(value);
        break;
    case MENELAUS_RTC_MON:
        s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
        break;
    case MENELAUS_RTC_YR:
        s->rtc.tm.tm_year = 2000 + from_bcd(value);
        break;
    case MENELAUS_RTC_WKDAY:
        s->rtc.tm.tm_mday = from_bcd(value);
        break;
    case MENELAUS_RTC_AL_SEC:
        s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_AL_MIN:
        s->rtc.alm.tm_min = from_bcd(value & 0x7f);
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_AL_HR:
        s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ?	/* MODE12_n24 */
                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
                from_bcd(value & 0x3f);
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_AL_DAY:
        s->rtc.alm.tm_mday = from_bcd(value);
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_AL_MON:
        s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_AL_YR:
        s->rtc.alm.tm_year = 2000 + from_bcd(value);
        menelaus_alm_update(s);
        break;
    case MENELAUS_RTC_COMP_MSB:
        s->rtc.comp &= 0xff;
        s->rtc.comp |= value << 8;
        break;
    case MENELAUS_RTC_COMP_LSB:
        s->rtc.comp &= 0xff << 8;
        s->rtc.comp |= value;
        break;

    case MENELAUS_S1_PULL_EN:
        s->pull[0] = value;
        break;
    case MENELAUS_S1_PULL_DIR:
        s->pull[1] = value & 0x1f;
        break;
    case MENELAUS_S2_PULL_EN:
        s->pull[2] = value;
        break;
    case MENELAUS_S2_PULL_DIR:
        s->pull[3] = value & 0x1f;
        break;

    case MENELAUS_MCT_CTRL1:
        s->mmc_ctrl[0] = value & 0x7f;
        break;
    case MENELAUS_MCT_CTRL2:
        s->mmc_ctrl[1] = value;
        /* TODO update Card Detect interrupts */
        break;
    case MENELAUS_MCT_CTRL3:
        s->mmc_ctrl[2] = value & 0xf;
        break;
    case MENELAUS_DEBOUNCE1:
        s->mmc_debounce = value & 0x3f;
        break;

    default:
#ifdef VERBOSE
        printf("%s: unknown register %02x\n", __func__, addr);
#endif
        break;
    }
}