|
|
1.1 ! root 1: /* ! 2: * TI TWL92230C energy-management companion device for the OMAP24xx. ! 3: * Aka. Menelaus (N4200 MENELAUS1_V2.2) ! 4: * ! 5: * Copyright (C) 2008 Nokia Corporation ! 6: * Written by Andrzej Zaborowski <[email protected]> ! 7: * ! 8: * This program is free software; you can redistribute it and/or ! 9: * modify it under the terms of the GNU General Public License as ! 10: * published by the Free Software Foundation; either version 2 or ! 11: * (at your option) version 3 of the License. ! 12: * ! 13: * This program is distributed in the hope that it will be useful, ! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: * GNU General Public License for more details. ! 17: * ! 18: * You should have received a copy of the GNU General Public License along ! 19: * with this program; if not, write to the Free Software Foundation, Inc., ! 20: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ! 21: */ ! 22: ! 23: #include "hw.h" ! 24: #include "qemu-timer.h" ! 25: #include "i2c.h" ! 26: #include "sysemu.h" ! 27: #include "console.h" ! 28: ! 29: #define VERBOSE 1 ! 30: ! 31: struct menelaus_s { ! 32: i2c_slave i2c; ! 33: qemu_irq irq; ! 34: ! 35: int firstbyte; ! 36: uint8_t reg; ! 37: ! 38: uint8_t vcore[5]; ! 39: uint8_t dcdc[3]; ! 40: uint8_t ldo[8]; ! 41: uint8_t sleep[2]; ! 42: uint8_t osc; ! 43: uint8_t detect; ! 44: uint16_t mask; ! 45: uint16_t status; ! 46: uint8_t dir; ! 47: uint8_t inputs; ! 48: uint8_t outputs; ! 49: uint8_t bbsms; ! 50: uint8_t pull[4]; ! 51: uint8_t mmc_ctrl[3]; ! 52: uint8_t mmc_debounce; ! 53: struct { ! 54: uint8_t ctrl; ! 55: uint16_t comp; ! 56: QEMUTimer *hz_tm; ! 57: int64_t next; ! 58: struct tm tm; ! 59: struct tm new; ! 60: struct tm alm; ! 61: int sec_offset; ! 62: int alm_sec; ! 63: int next_comp; ! 64: } rtc; ! 65: qemu_irq handler[3]; ! 66: qemu_irq *in; ! 67: int pwrbtn_state; ! 68: qemu_irq pwrbtn; ! 69: }; ! 70: ! 71: static inline void menelaus_update(struct menelaus_s *s) ! 72: { ! 73: qemu_set_irq(s->irq, s->status & ~s->mask); ! 74: } ! 75: ! 76: static inline void menelaus_rtc_start(struct menelaus_s *s) ! 77: { ! 78: s->rtc.next =+ qemu_get_clock(rt_clock); ! 79: qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); ! 80: } ! 81: ! 82: static inline void menelaus_rtc_stop(struct menelaus_s *s) ! 83: { ! 84: qemu_del_timer(s->rtc.hz_tm); ! 85: s->rtc.next =- qemu_get_clock(rt_clock); ! 86: if (s->rtc.next < 1) ! 87: s->rtc.next = 1; ! 88: } ! 89: ! 90: static void menelaus_rtc_update(struct menelaus_s *s) ! 91: { ! 92: qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset); ! 93: } ! 94: ! 95: static void menelaus_alm_update(struct menelaus_s *s) ! 96: { ! 97: if ((s->rtc.ctrl & 3) == 3) ! 98: s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset; ! 99: } ! 100: ! 101: static void menelaus_rtc_hz(void *opaque) ! 102: { ! 103: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 104: ! 105: s->rtc.next_comp --; ! 106: s->rtc.alm_sec --; ! 107: s->rtc.next += 1000; ! 108: qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); ! 109: if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */ ! 110: menelaus_rtc_update(s); ! 111: if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec) ! 112: s->status |= 1 << 8; /* RTCTMR */ ! 113: else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min) ! 114: s->status |= 1 << 8; /* RTCTMR */ ! 115: else if (!s->rtc.tm.tm_hour) ! 116: s->status |= 1 << 8; /* RTCTMR */ ! 117: } else ! 118: s->status |= 1 << 8; /* RTCTMR */ ! 119: if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */ ! 120: if (s->rtc.alm_sec == 0) ! 121: s->status |= 1 << 9; /* RTCALM */ ! 122: /* TODO: wake-up */ ! 123: } ! 124: if (s->rtc.next_comp <= 0) { ! 125: s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000); ! 126: s->rtc.next_comp = 3600; ! 127: } ! 128: menelaus_update(s); ! 129: } ! 130: ! 131: static void menelaus_reset(i2c_slave *i2c) ! 132: { ! 133: struct menelaus_s *s = (struct menelaus_s *) i2c; ! 134: s->reg = 0x00; ! 135: ! 136: s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */ ! 137: s->vcore[1] = 0x05; ! 138: s->vcore[2] = 0x02; ! 139: s->vcore[3] = 0x0c; ! 140: s->vcore[4] = 0x03; ! 141: s->dcdc[0] = 0x33; /* Depends on wiring */ ! 142: s->dcdc[1] = 0x03; ! 143: s->dcdc[2] = 0x00; ! 144: s->ldo[0] = 0x95; ! 145: s->ldo[1] = 0x7e; ! 146: s->ldo[2] = 0x00; ! 147: s->ldo[3] = 0x00; /* Depends on wiring */ ! 148: s->ldo[4] = 0x03; /* Depends on wiring */ ! 149: s->ldo[5] = 0x00; ! 150: s->ldo[6] = 0x00; ! 151: s->ldo[7] = 0x00; ! 152: s->sleep[0] = 0x00; ! 153: s->sleep[1] = 0x00; ! 154: s->osc = 0x01; ! 155: s->detect = 0x09; ! 156: s->mask = 0x0fff; ! 157: s->status = 0; ! 158: s->dir = 0x07; ! 159: s->outputs = 0x00; ! 160: s->bbsms = 0x00; ! 161: s->pull[0] = 0x00; ! 162: s->pull[1] = 0x00; ! 163: s->pull[2] = 0x00; ! 164: s->pull[3] = 0x00; ! 165: s->mmc_ctrl[0] = 0x03; ! 166: s->mmc_ctrl[1] = 0xc0; ! 167: s->mmc_ctrl[2] = 0x00; ! 168: s->mmc_debounce = 0x05; ! 169: ! 170: if (s->rtc.ctrl & 1) ! 171: menelaus_rtc_stop(s); ! 172: s->rtc.ctrl = 0x00; ! 173: s->rtc.comp = 0x0000; ! 174: s->rtc.next = 1000; ! 175: s->rtc.sec_offset = 0; ! 176: s->rtc.next_comp = 1800; ! 177: s->rtc.alm_sec = 1800; ! 178: s->rtc.alm.tm_sec = 0x00; ! 179: s->rtc.alm.tm_min = 0x00; ! 180: s->rtc.alm.tm_hour = 0x00; ! 181: s->rtc.alm.tm_mday = 0x01; ! 182: s->rtc.alm.tm_mon = 0x00; ! 183: s->rtc.alm.tm_year = 2004; ! 184: menelaus_update(s); ! 185: } ! 186: ! 187: static inline uint8_t to_bcd(int val) ! 188: { ! 189: return ((val / 10) << 4) | (val % 10); ! 190: } ! 191: ! 192: static inline int from_bcd(uint8_t val) ! 193: { ! 194: return ((val >> 4) * 10) + (val & 0x0f); ! 195: } ! 196: ! 197: static void menelaus_gpio_set(void *opaque, int line, int level) ! 198: { ! 199: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 200: ! 201: /* No interrupt generated */ ! 202: s->inputs &= ~(1 << line); ! 203: s->inputs |= level << line; ! 204: } ! 205: ! 206: static void menelaus_pwrbtn_set(void *opaque, int line, int level) ! 207: { ! 208: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 209: ! 210: if (!s->pwrbtn_state && level) { ! 211: s->status |= 1 << 11; /* PSHBTN */ ! 212: menelaus_update(s); ! 213: } ! 214: s->pwrbtn_state = level; ! 215: } ! 216: ! 217: #define MENELAUS_REV 0x01 ! 218: #define MENELAUS_VCORE_CTRL1 0x02 ! 219: #define MENELAUS_VCORE_CTRL2 0x03 ! 220: #define MENELAUS_VCORE_CTRL3 0x04 ! 221: #define MENELAUS_VCORE_CTRL4 0x05 ! 222: #define MENELAUS_VCORE_CTRL5 0x06 ! 223: #define MENELAUS_DCDC_CTRL1 0x07 ! 224: #define MENELAUS_DCDC_CTRL2 0x08 ! 225: #define MENELAUS_DCDC_CTRL3 0x09 ! 226: #define MENELAUS_LDO_CTRL1 0x0a ! 227: #define MENELAUS_LDO_CTRL2 0x0b ! 228: #define MENELAUS_LDO_CTRL3 0x0c ! 229: #define MENELAUS_LDO_CTRL4 0x0d ! 230: #define MENELAUS_LDO_CTRL5 0x0e ! 231: #define MENELAUS_LDO_CTRL6 0x0f ! 232: #define MENELAUS_LDO_CTRL7 0x10 ! 233: #define MENELAUS_LDO_CTRL8 0x11 ! 234: #define MENELAUS_SLEEP_CTRL1 0x12 ! 235: #define MENELAUS_SLEEP_CTRL2 0x13 ! 236: #define MENELAUS_DEVICE_OFF 0x14 ! 237: #define MENELAUS_OSC_CTRL 0x15 ! 238: #define MENELAUS_DETECT_CTRL 0x16 ! 239: #define MENELAUS_INT_MASK1 0x17 ! 240: #define MENELAUS_INT_MASK2 0x18 ! 241: #define MENELAUS_INT_STATUS1 0x19 ! 242: #define MENELAUS_INT_STATUS2 0x1a ! 243: #define MENELAUS_INT_ACK1 0x1b ! 244: #define MENELAUS_INT_ACK2 0x1c ! 245: #define MENELAUS_GPIO_CTRL 0x1d ! 246: #define MENELAUS_GPIO_IN 0x1e ! 247: #define MENELAUS_GPIO_OUT 0x1f ! 248: #define MENELAUS_BBSMS 0x20 ! 249: #define MENELAUS_RTC_CTRL 0x21 ! 250: #define MENELAUS_RTC_UPDATE 0x22 ! 251: #define MENELAUS_RTC_SEC 0x23 ! 252: #define MENELAUS_RTC_MIN 0x24 ! 253: #define MENELAUS_RTC_HR 0x25 ! 254: #define MENELAUS_RTC_DAY 0x26 ! 255: #define MENELAUS_RTC_MON 0x27 ! 256: #define MENELAUS_RTC_YR 0x28 ! 257: #define MENELAUS_RTC_WKDAY 0x29 ! 258: #define MENELAUS_RTC_AL_SEC 0x2a ! 259: #define MENELAUS_RTC_AL_MIN 0x2b ! 260: #define MENELAUS_RTC_AL_HR 0x2c ! 261: #define MENELAUS_RTC_AL_DAY 0x2d ! 262: #define MENELAUS_RTC_AL_MON 0x2e ! 263: #define MENELAUS_RTC_AL_YR 0x2f ! 264: #define MENELAUS_RTC_COMP_MSB 0x30 ! 265: #define MENELAUS_RTC_COMP_LSB 0x31 ! 266: #define MENELAUS_S1_PULL_EN 0x32 ! 267: #define MENELAUS_S1_PULL_DIR 0x33 ! 268: #define MENELAUS_S2_PULL_EN 0x34 ! 269: #define MENELAUS_S2_PULL_DIR 0x35 ! 270: #define MENELAUS_MCT_CTRL1 0x36 ! 271: #define MENELAUS_MCT_CTRL2 0x37 ! 272: #define MENELAUS_MCT_CTRL3 0x38 ! 273: #define MENELAUS_MCT_PIN_ST 0x39 ! 274: #define MENELAUS_DEBOUNCE1 0x3a ! 275: ! 276: static uint8_t menelaus_read(void *opaque, uint8_t addr) ! 277: { ! 278: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 279: int reg = 0; ! 280: ! 281: switch (addr) { ! 282: case MENELAUS_REV: ! 283: return 0x22; ! 284: ! 285: case MENELAUS_VCORE_CTRL5: reg ++; ! 286: case MENELAUS_VCORE_CTRL4: reg ++; ! 287: case MENELAUS_VCORE_CTRL3: reg ++; ! 288: case MENELAUS_VCORE_CTRL2: reg ++; ! 289: case MENELAUS_VCORE_CTRL1: ! 290: return s->vcore[reg]; ! 291: ! 292: case MENELAUS_DCDC_CTRL3: reg ++; ! 293: case MENELAUS_DCDC_CTRL2: reg ++; ! 294: case MENELAUS_DCDC_CTRL1: ! 295: return s->dcdc[reg]; ! 296: ! 297: case MENELAUS_LDO_CTRL8: reg ++; ! 298: case MENELAUS_LDO_CTRL7: reg ++; ! 299: case MENELAUS_LDO_CTRL6: reg ++; ! 300: case MENELAUS_LDO_CTRL5: reg ++; ! 301: case MENELAUS_LDO_CTRL4: reg ++; ! 302: case MENELAUS_LDO_CTRL3: reg ++; ! 303: case MENELAUS_LDO_CTRL2: reg ++; ! 304: case MENELAUS_LDO_CTRL1: ! 305: return s->ldo[reg]; ! 306: ! 307: case MENELAUS_SLEEP_CTRL2: reg ++; ! 308: case MENELAUS_SLEEP_CTRL1: ! 309: return s->sleep[reg]; ! 310: ! 311: case MENELAUS_DEVICE_OFF: ! 312: return 0; ! 313: ! 314: case MENELAUS_OSC_CTRL: ! 315: return s->osc | (1 << 7); /* CLK32K_GOOD */ ! 316: ! 317: case MENELAUS_DETECT_CTRL: ! 318: return s->detect; ! 319: ! 320: case MENELAUS_INT_MASK1: ! 321: return (s->mask >> 0) & 0xff; ! 322: case MENELAUS_INT_MASK2: ! 323: return (s->mask >> 8) & 0xff; ! 324: ! 325: case MENELAUS_INT_STATUS1: ! 326: return (s->status >> 0) & 0xff; ! 327: case MENELAUS_INT_STATUS2: ! 328: return (s->status >> 8) & 0xff; ! 329: ! 330: case MENELAUS_INT_ACK1: ! 331: case MENELAUS_INT_ACK2: ! 332: return 0; ! 333: ! 334: case MENELAUS_GPIO_CTRL: ! 335: return s->dir; ! 336: case MENELAUS_GPIO_IN: ! 337: return s->inputs | (~s->dir & s->outputs); ! 338: case MENELAUS_GPIO_OUT: ! 339: return s->outputs; ! 340: ! 341: case MENELAUS_BBSMS: ! 342: return s->bbsms; ! 343: ! 344: case MENELAUS_RTC_CTRL: ! 345: return s->rtc.ctrl; ! 346: case MENELAUS_RTC_UPDATE: ! 347: return 0x00; ! 348: case MENELAUS_RTC_SEC: ! 349: menelaus_rtc_update(s); ! 350: return to_bcd(s->rtc.tm.tm_sec); ! 351: case MENELAUS_RTC_MIN: ! 352: menelaus_rtc_update(s); ! 353: return to_bcd(s->rtc.tm.tm_min); ! 354: case MENELAUS_RTC_HR: ! 355: menelaus_rtc_update(s); ! 356: if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ ! 357: return to_bcd((s->rtc.tm.tm_hour % 12) + 1) | ! 358: (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */ ! 359: else ! 360: return to_bcd(s->rtc.tm.tm_hour); ! 361: case MENELAUS_RTC_DAY: ! 362: menelaus_rtc_update(s); ! 363: return to_bcd(s->rtc.tm.tm_mday); ! 364: case MENELAUS_RTC_MON: ! 365: menelaus_rtc_update(s); ! 366: return to_bcd(s->rtc.tm.tm_mon + 1); ! 367: case MENELAUS_RTC_YR: ! 368: menelaus_rtc_update(s); ! 369: return to_bcd(s->rtc.tm.tm_year - 2000); ! 370: case MENELAUS_RTC_WKDAY: ! 371: menelaus_rtc_update(s); ! 372: return to_bcd(s->rtc.tm.tm_wday); ! 373: case MENELAUS_RTC_AL_SEC: ! 374: return to_bcd(s->rtc.alm.tm_sec); ! 375: case MENELAUS_RTC_AL_MIN: ! 376: return to_bcd(s->rtc.alm.tm_min); ! 377: case MENELAUS_RTC_AL_HR: ! 378: if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ ! 379: return to_bcd((s->rtc.alm.tm_hour % 12) + 1) | ! 380: (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */ ! 381: else ! 382: return to_bcd(s->rtc.alm.tm_hour); ! 383: case MENELAUS_RTC_AL_DAY: ! 384: return to_bcd(s->rtc.alm.tm_mday); ! 385: case MENELAUS_RTC_AL_MON: ! 386: return to_bcd(s->rtc.alm.tm_mon + 1); ! 387: case MENELAUS_RTC_AL_YR: ! 388: return to_bcd(s->rtc.alm.tm_year - 2000); ! 389: case MENELAUS_RTC_COMP_MSB: ! 390: return (s->rtc.comp >> 8) & 0xff; ! 391: case MENELAUS_RTC_COMP_LSB: ! 392: return (s->rtc.comp >> 0) & 0xff; ! 393: ! 394: case MENELAUS_S1_PULL_EN: ! 395: return s->pull[0]; ! 396: case MENELAUS_S1_PULL_DIR: ! 397: return s->pull[1]; ! 398: case MENELAUS_S2_PULL_EN: ! 399: return s->pull[2]; ! 400: case MENELAUS_S2_PULL_DIR: ! 401: return s->pull[3]; ! 402: ! 403: case MENELAUS_MCT_CTRL3: reg ++; ! 404: case MENELAUS_MCT_CTRL2: reg ++; ! 405: case MENELAUS_MCT_CTRL1: ! 406: return s->mmc_ctrl[reg]; ! 407: case MENELAUS_MCT_PIN_ST: ! 408: /* TODO: return the real Card Detect */ ! 409: return 0; ! 410: case MENELAUS_DEBOUNCE1: ! 411: return s->mmc_debounce; ! 412: ! 413: default: ! 414: #ifdef VERBOSE ! 415: printf("%s: unknown register %02x\n", __FUNCTION__, addr); ! 416: #endif ! 417: break; ! 418: } ! 419: return 0; ! 420: } ! 421: ! 422: static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) ! 423: { ! 424: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 425: int line; ! 426: int reg = 0; ! 427: struct tm tm; ! 428: ! 429: switch (addr) { ! 430: case MENELAUS_VCORE_CTRL1: ! 431: s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12); ! 432: break; ! 433: case MENELAUS_VCORE_CTRL2: ! 434: s->vcore[1] = value; ! 435: break; ! 436: case MENELAUS_VCORE_CTRL3: ! 437: s->vcore[2] = MIN(value & 0x1f, 0x12); ! 438: break; ! 439: case MENELAUS_VCORE_CTRL4: ! 440: s->vcore[3] = MIN(value & 0x1f, 0x12); ! 441: break; ! 442: case MENELAUS_VCORE_CTRL5: ! 443: s->vcore[4] = value & 3; ! 444: /* XXX ! 445: * auto set to 3 on M_Active, nRESWARM ! 446: * auto set to 0 on M_WaitOn, M_Backup ! 447: */ ! 448: break; ! 449: ! 450: case MENELAUS_DCDC_CTRL1: ! 451: s->dcdc[0] = value & 0x3f; ! 452: break; ! 453: case MENELAUS_DCDC_CTRL2: ! 454: s->dcdc[1] = value & 0x07; ! 455: /* XXX ! 456: * auto set to 3 on M_Active, nRESWARM ! 457: * auto set to 0 on M_WaitOn, M_Backup ! 458: */ ! 459: break; ! 460: case MENELAUS_DCDC_CTRL3: ! 461: s->dcdc[2] = value & 0x07; ! 462: break; ! 463: ! 464: case MENELAUS_LDO_CTRL1: ! 465: s->ldo[0] = value; ! 466: break; ! 467: case MENELAUS_LDO_CTRL2: ! 468: s->ldo[1] = value & 0x7f; ! 469: /* XXX ! 470: * auto set to 0x7e on M_WaitOn, M_Backup ! 471: */ ! 472: break; ! 473: case MENELAUS_LDO_CTRL3: ! 474: s->ldo[2] = value & 3; ! 475: /* XXX ! 476: * auto set to 3 on M_Active, nRESWARM ! 477: * auto set to 0 on M_WaitOn, M_Backup ! 478: */ ! 479: break; ! 480: case MENELAUS_LDO_CTRL4: ! 481: s->ldo[3] = value & 3; ! 482: /* XXX ! 483: * auto set to 3 on M_Active, nRESWARM ! 484: * auto set to 0 on M_WaitOn, M_Backup ! 485: */ ! 486: break; ! 487: case MENELAUS_LDO_CTRL5: ! 488: s->ldo[4] = value & 3; ! 489: /* XXX ! 490: * auto set to 3 on M_Active, nRESWARM ! 491: * auto set to 0 on M_WaitOn, M_Backup ! 492: */ ! 493: break; ! 494: case MENELAUS_LDO_CTRL6: ! 495: s->ldo[5] = value & 3; ! 496: break; ! 497: case MENELAUS_LDO_CTRL7: ! 498: s->ldo[6] = value & 3; ! 499: break; ! 500: case MENELAUS_LDO_CTRL8: ! 501: s->ldo[7] = value & 3; ! 502: break; ! 503: ! 504: case MENELAUS_SLEEP_CTRL2: reg ++; ! 505: case MENELAUS_SLEEP_CTRL1: ! 506: s->sleep[reg] = value; ! 507: break; ! 508: ! 509: case MENELAUS_DEVICE_OFF: ! 510: if (value & 1) ! 511: menelaus_reset(&s->i2c); ! 512: break; ! 513: ! 514: case MENELAUS_OSC_CTRL: ! 515: s->osc = value & 7; ! 516: break; ! 517: ! 518: case MENELAUS_DETECT_CTRL: ! 519: s->detect = value & 0x7f; ! 520: break; ! 521: ! 522: case MENELAUS_INT_MASK1: ! 523: s->mask &= 0xf00; ! 524: s->mask |= value << 0; ! 525: menelaus_update(s); ! 526: break; ! 527: case MENELAUS_INT_MASK2: ! 528: s->mask &= 0x0ff; ! 529: s->mask |= value << 8; ! 530: menelaus_update(s); ! 531: break; ! 532: ! 533: case MENELAUS_INT_ACK1: ! 534: s->status &= ~(((uint16_t) value) << 0); ! 535: menelaus_update(s); ! 536: break; ! 537: case MENELAUS_INT_ACK2: ! 538: s->status &= ~(((uint16_t) value) << 8); ! 539: menelaus_update(s); ! 540: break; ! 541: ! 542: case MENELAUS_GPIO_CTRL: ! 543: for (line = 0; line < 3; line ++) ! 544: if (((s->dir ^ value) >> line) & 1) ! 545: if (s->handler[line]) ! 546: qemu_set_irq(s->handler[line], ! 547: ((s->outputs & ~s->dir) >> line) & 1); ! 548: s->dir = value & 0x67; ! 549: break; ! 550: case MENELAUS_GPIO_OUT: ! 551: for (line = 0; line < 3; line ++) ! 552: if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) ! 553: if (s->handler[line]) ! 554: qemu_set_irq(s->handler[line], (s->outputs >> line) & 1); ! 555: s->outputs = value & 0x07; ! 556: break; ! 557: ! 558: case MENELAUS_BBSMS: ! 559: s->bbsms = 0x0d; ! 560: break; ! 561: ! 562: case MENELAUS_RTC_CTRL: ! 563: if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */ ! 564: if (value & 1) ! 565: menelaus_rtc_start(s); ! 566: else ! 567: menelaus_rtc_stop(s); ! 568: } ! 569: s->rtc.ctrl = value & 0x1f; ! 570: menelaus_alm_update(s); ! 571: break; ! 572: case MENELAUS_RTC_UPDATE: ! 573: menelaus_rtc_update(s); ! 574: memcpy(&tm, &s->rtc.tm, sizeof(tm)); ! 575: switch (value & 0xf) { ! 576: case 0: ! 577: break; ! 578: case 1: ! 579: tm.tm_sec = s->rtc.new.tm_sec; ! 580: break; ! 581: case 2: ! 582: tm.tm_min = s->rtc.new.tm_min; ! 583: break; ! 584: case 3: ! 585: if (s->rtc.new.tm_hour > 23) ! 586: goto rtc_badness; ! 587: tm.tm_hour = s->rtc.new.tm_hour; ! 588: break; ! 589: case 4: ! 590: if (s->rtc.new.tm_mday < 1) ! 591: goto rtc_badness; ! 592: /* TODO check range */ ! 593: tm.tm_mday = s->rtc.new.tm_mday; ! 594: break; ! 595: case 5: ! 596: if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) ! 597: goto rtc_badness; ! 598: tm.tm_mon = s->rtc.new.tm_mon; ! 599: break; ! 600: case 6: ! 601: tm.tm_year = s->rtc.new.tm_year; ! 602: break; ! 603: case 7: ! 604: /* TODO set .tm_mday instead */ ! 605: tm.tm_wday = s->rtc.new.tm_wday; ! 606: break; ! 607: case 8: ! 608: if (s->rtc.new.tm_hour > 23) ! 609: goto rtc_badness; ! 610: if (s->rtc.new.tm_mday < 1) ! 611: goto rtc_badness; ! 612: if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) ! 613: goto rtc_badness; ! 614: tm.tm_sec = s->rtc.new.tm_sec; ! 615: tm.tm_min = s->rtc.new.tm_min; ! 616: tm.tm_hour = s->rtc.new.tm_hour; ! 617: tm.tm_mday = s->rtc.new.tm_mday; ! 618: tm.tm_mon = s->rtc.new.tm_mon; ! 619: tm.tm_year = s->rtc.new.tm_year; ! 620: break; ! 621: rtc_badness: ! 622: default: ! 623: fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n", ! 624: __FUNCTION__, value); ! 625: s->status |= 1 << 10; /* RTCERR */ ! 626: menelaus_update(s); ! 627: } ! 628: s->rtc.sec_offset = qemu_timedate_diff(&tm); ! 629: break; ! 630: case MENELAUS_RTC_SEC: ! 631: s->rtc.tm.tm_sec = from_bcd(value & 0x7f); ! 632: break; ! 633: case MENELAUS_RTC_MIN: ! 634: s->rtc.tm.tm_min = from_bcd(value & 0x7f); ! 635: break; ! 636: case MENELAUS_RTC_HR: ! 637: s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ ! 638: MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : ! 639: from_bcd(value & 0x3f); ! 640: break; ! 641: case MENELAUS_RTC_DAY: ! 642: s->rtc.tm.tm_mday = from_bcd(value); ! 643: break; ! 644: case MENELAUS_RTC_MON: ! 645: s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1; ! 646: break; ! 647: case MENELAUS_RTC_YR: ! 648: s->rtc.tm.tm_year = 2000 + from_bcd(value); ! 649: break; ! 650: case MENELAUS_RTC_WKDAY: ! 651: s->rtc.tm.tm_mday = from_bcd(value); ! 652: break; ! 653: case MENELAUS_RTC_AL_SEC: ! 654: s->rtc.alm.tm_sec = from_bcd(value & 0x7f); ! 655: menelaus_alm_update(s); ! 656: break; ! 657: case MENELAUS_RTC_AL_MIN: ! 658: s->rtc.alm.tm_min = from_bcd(value & 0x7f); ! 659: menelaus_alm_update(s); ! 660: break; ! 661: case MENELAUS_RTC_AL_HR: ! 662: s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ ! 663: MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : ! 664: from_bcd(value & 0x3f); ! 665: menelaus_alm_update(s); ! 666: break; ! 667: case MENELAUS_RTC_AL_DAY: ! 668: s->rtc.alm.tm_mday = from_bcd(value); ! 669: menelaus_alm_update(s); ! 670: break; ! 671: case MENELAUS_RTC_AL_MON: ! 672: s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1; ! 673: menelaus_alm_update(s); ! 674: break; ! 675: case MENELAUS_RTC_AL_YR: ! 676: s->rtc.alm.tm_year = 2000 + from_bcd(value); ! 677: menelaus_alm_update(s); ! 678: break; ! 679: case MENELAUS_RTC_COMP_MSB: ! 680: s->rtc.comp &= 0xff; ! 681: s->rtc.comp |= value << 8; ! 682: break; ! 683: case MENELAUS_RTC_COMP_LSB: ! 684: s->rtc.comp &= 0xff << 8; ! 685: s->rtc.comp |= value; ! 686: break; ! 687: ! 688: case MENELAUS_S1_PULL_EN: ! 689: s->pull[0] = value; ! 690: break; ! 691: case MENELAUS_S1_PULL_DIR: ! 692: s->pull[1] = value & 0x1f; ! 693: break; ! 694: case MENELAUS_S2_PULL_EN: ! 695: s->pull[2] = value; ! 696: break; ! 697: case MENELAUS_S2_PULL_DIR: ! 698: s->pull[3] = value & 0x1f; ! 699: break; ! 700: ! 701: case MENELAUS_MCT_CTRL1: ! 702: s->mmc_ctrl[0] = value & 0x7f; ! 703: break; ! 704: case MENELAUS_MCT_CTRL2: ! 705: s->mmc_ctrl[1] = value; ! 706: /* TODO update Card Detect interrupts */ ! 707: break; ! 708: case MENELAUS_MCT_CTRL3: ! 709: s->mmc_ctrl[2] = value & 0xf; ! 710: break; ! 711: case MENELAUS_DEBOUNCE1: ! 712: s->mmc_debounce = value & 0x3f; ! 713: break; ! 714: ! 715: default: ! 716: #ifdef VERBOSE ! 717: printf("%s: unknown register %02x\n", __FUNCTION__, addr); ! 718: #endif ! 719: } ! 720: } ! 721: ! 722: static void menelaus_event(i2c_slave *i2c, enum i2c_event event) ! 723: { ! 724: struct menelaus_s *s = (struct menelaus_s *) i2c; ! 725: ! 726: if (event == I2C_START_SEND) ! 727: s->firstbyte = 1; ! 728: } ! 729: ! 730: static int menelaus_tx(i2c_slave *i2c, uint8_t data) ! 731: { ! 732: struct menelaus_s *s = (struct menelaus_s *) i2c; ! 733: /* Interpret register address byte */ ! 734: if (s->firstbyte) { ! 735: s->reg = data; ! 736: s->firstbyte = 0; ! 737: } else ! 738: menelaus_write(s, s->reg ++, data); ! 739: ! 740: return 0; ! 741: } ! 742: ! 743: static int menelaus_rx(i2c_slave *i2c) ! 744: { ! 745: struct menelaus_s *s = (struct menelaus_s *) i2c; ! 746: ! 747: return menelaus_read(s, s->reg ++); ! 748: } ! 749: ! 750: static void tm_put(QEMUFile *f, struct tm *tm) { ! 751: qemu_put_be16(f, tm->tm_sec); ! 752: qemu_put_be16(f, tm->tm_min); ! 753: qemu_put_be16(f, tm->tm_hour); ! 754: qemu_put_be16(f, tm->tm_mday); ! 755: qemu_put_be16(f, tm->tm_min); ! 756: qemu_put_be16(f, tm->tm_year); ! 757: } ! 758: ! 759: static void tm_get(QEMUFile *f, struct tm *tm) { ! 760: tm->tm_sec = qemu_get_be16(f); ! 761: tm->tm_min = qemu_get_be16(f); ! 762: tm->tm_hour = qemu_get_be16(f); ! 763: tm->tm_mday = qemu_get_be16(f); ! 764: tm->tm_min = qemu_get_be16(f); ! 765: tm->tm_year = qemu_get_be16(f); ! 766: } ! 767: ! 768: static void menelaus_save(QEMUFile *f, void *opaque) ! 769: { ! 770: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 771: ! 772: qemu_put_be32(f, s->firstbyte); ! 773: qemu_put_8s(f, &s->reg); ! 774: ! 775: qemu_put_8s(f, &s->vcore[0]); ! 776: qemu_put_8s(f, &s->vcore[1]); ! 777: qemu_put_8s(f, &s->vcore[2]); ! 778: qemu_put_8s(f, &s->vcore[3]); ! 779: qemu_put_8s(f, &s->vcore[4]); ! 780: qemu_put_8s(f, &s->dcdc[3]); ! 781: qemu_put_8s(f, &s->dcdc[3]); ! 782: qemu_put_8s(f, &s->dcdc[3]); ! 783: qemu_put_8s(f, &s->ldo[0]); ! 784: qemu_put_8s(f, &s->ldo[1]); ! 785: qemu_put_8s(f, &s->ldo[2]); ! 786: qemu_put_8s(f, &s->ldo[3]); ! 787: qemu_put_8s(f, &s->ldo[4]); ! 788: qemu_put_8s(f, &s->ldo[5]); ! 789: qemu_put_8s(f, &s->ldo[6]); ! 790: qemu_put_8s(f, &s->ldo[7]); ! 791: qemu_put_8s(f, &s->sleep[0]); ! 792: qemu_put_8s(f, &s->sleep[1]); ! 793: qemu_put_8s(f, &s->osc); ! 794: qemu_put_8s(f, &s->detect); ! 795: qemu_put_be16s(f, &s->mask); ! 796: qemu_put_be16s(f, &s->status); ! 797: qemu_put_8s(f, &s->dir); ! 798: qemu_put_8s(f, &s->inputs); ! 799: qemu_put_8s(f, &s->outputs); ! 800: qemu_put_8s(f, &s->bbsms); ! 801: qemu_put_8s(f, &s->pull[0]); ! 802: qemu_put_8s(f, &s->pull[1]); ! 803: qemu_put_8s(f, &s->pull[2]); ! 804: qemu_put_8s(f, &s->pull[3]); ! 805: qemu_put_8s(f, &s->mmc_ctrl[0]); ! 806: qemu_put_8s(f, &s->mmc_ctrl[1]); ! 807: qemu_put_8s(f, &s->mmc_ctrl[2]); ! 808: qemu_put_8s(f, &s->mmc_debounce); ! 809: qemu_put_8s(f, &s->rtc.ctrl); ! 810: qemu_put_be16s(f, &s->rtc.comp); ! 811: /* Should be <= 1000 */ ! 812: qemu_put_be16(f, s->rtc.next - qemu_get_clock(rt_clock)); ! 813: tm_put(f, &s->rtc.new); ! 814: tm_put(f, &s->rtc.alm); ! 815: qemu_put_byte(f, s->pwrbtn_state); ! 816: ! 817: i2c_slave_save(f, &s->i2c); ! 818: } ! 819: ! 820: static int menelaus_load(QEMUFile *f, void *opaque, int version_id) ! 821: { ! 822: struct menelaus_s *s = (struct menelaus_s *) opaque; ! 823: ! 824: s->firstbyte = qemu_get_be32(f); ! 825: qemu_get_8s(f, &s->reg); ! 826: ! 827: if (s->rtc.ctrl & 1) /* RTC_EN */ ! 828: menelaus_rtc_stop(s); ! 829: qemu_get_8s(f, &s->vcore[0]); ! 830: qemu_get_8s(f, &s->vcore[1]); ! 831: qemu_get_8s(f, &s->vcore[2]); ! 832: qemu_get_8s(f, &s->vcore[3]); ! 833: qemu_get_8s(f, &s->vcore[4]); ! 834: qemu_get_8s(f, &s->dcdc[3]); ! 835: qemu_get_8s(f, &s->dcdc[3]); ! 836: qemu_get_8s(f, &s->dcdc[3]); ! 837: qemu_get_8s(f, &s->ldo[0]); ! 838: qemu_get_8s(f, &s->ldo[1]); ! 839: qemu_get_8s(f, &s->ldo[2]); ! 840: qemu_get_8s(f, &s->ldo[3]); ! 841: qemu_get_8s(f, &s->ldo[4]); ! 842: qemu_get_8s(f, &s->ldo[5]); ! 843: qemu_get_8s(f, &s->ldo[6]); ! 844: qemu_get_8s(f, &s->ldo[7]); ! 845: qemu_get_8s(f, &s->sleep[0]); ! 846: qemu_get_8s(f, &s->sleep[1]); ! 847: qemu_get_8s(f, &s->osc); ! 848: qemu_get_8s(f, &s->detect); ! 849: qemu_get_be16s(f, &s->mask); ! 850: qemu_get_be16s(f, &s->status); ! 851: qemu_get_8s(f, &s->dir); ! 852: qemu_get_8s(f, &s->inputs); ! 853: qemu_get_8s(f, &s->outputs); ! 854: qemu_get_8s(f, &s->bbsms); ! 855: qemu_get_8s(f, &s->pull[0]); ! 856: qemu_get_8s(f, &s->pull[1]); ! 857: qemu_get_8s(f, &s->pull[2]); ! 858: qemu_get_8s(f, &s->pull[3]); ! 859: qemu_get_8s(f, &s->mmc_ctrl[0]); ! 860: qemu_get_8s(f, &s->mmc_ctrl[1]); ! 861: qemu_get_8s(f, &s->mmc_ctrl[2]); ! 862: qemu_get_8s(f, &s->mmc_debounce); ! 863: qemu_get_8s(f, &s->rtc.ctrl); ! 864: qemu_get_be16s(f, &s->rtc.comp); ! 865: s->rtc.next = qemu_get_be16(f); ! 866: tm_get(f, &s->rtc.new); ! 867: tm_get(f, &s->rtc.alm); ! 868: s->pwrbtn_state = qemu_get_byte(f); ! 869: menelaus_alm_update(s); ! 870: menelaus_update(s); ! 871: if (s->rtc.ctrl & 1) /* RTC_EN */ ! 872: menelaus_rtc_start(s); ! 873: ! 874: i2c_slave_load(f, &s->i2c); ! 875: return 0; ! 876: } ! 877: ! 878: i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq) ! 879: { ! 880: struct menelaus_s *s = (struct menelaus_s *) ! 881: i2c_slave_init(bus, 0, sizeof(struct menelaus_s)); ! 882: ! 883: s->i2c.event = menelaus_event; ! 884: s->i2c.recv = menelaus_rx; ! 885: s->i2c.send = menelaus_tx; ! 886: ! 887: s->irq = irq; ! 888: s->rtc.hz_tm = qemu_new_timer(rt_clock, menelaus_rtc_hz, s); ! 889: s->in = qemu_allocate_irqs(menelaus_gpio_set, s, 3); ! 890: s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0]; ! 891: ! 892: menelaus_reset(&s->i2c); ! 893: ! 894: register_savevm("menelaus", -1, 0, menelaus_save, menelaus_load, s); ! 895: ! 896: return &s->i2c; ! 897: } ! 898: ! 899: qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c) ! 900: { ! 901: struct menelaus_s *s = (struct menelaus_s *) i2c; ! 902: ! 903: return s->in; ! 904: } ! 905: ! 906: void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) ! 907: { ! 908: struct menelaus_s *s = (struct menelaus_s *) i2c; ! 909: ! 910: if (line >= 3 || line < 0) { ! 911: fprintf(stderr, "%s: No GPO line %i\n", __FUNCTION__, line); ! 912: exit(-1); ! 913: } ! 914: s->handler[line] = handler; ! 915: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.