|
|
1.1 ! root 1: /* $Id: ad184x.c,v 1.1 2009/06/17 22:41:30 fredette Exp $ */ ! 2: ! 3: /* ic/ad184x.c - Analog Devices 184x (and Crystal Semiconductors 4248 ! 4: and 423x) implementation: */ ! 5: ! 6: /* ! 7: * Copyright (c) 2009 Matt Fredette ! 8: * All rights reserved. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by Matt Fredette. ! 21: * 4. The name of the author may not be used to endorse or promote products ! 22: * derived from this software without specific prior written permission. ! 23: * ! 24: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 26: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 27: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 28: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 29: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 30: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 32: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 33: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 34: * POSSIBILITY OF SUCH DAMAGE. ! 35: */ ! 36: ! 37: #include <tme/common.h> ! 38: _TME_RCSID("$Id: ad184x.c,v 1.1 2009/06/17 22:41:30 fredette Exp $"); ! 39: ! 40: /* includes: */ ! 41: #include <tme/completion.h> ! 42: #include <tme/generic/bus-device.h> ! 43: ! 44: /* macros: */ ! 45: ! 46: /* the different parts: */ ! 47: #define TME_AD184X_PART_AD1848 (0) ! 48: #define TME_AD184X_PART_CS4231 (10) ! 49: #define TME_AD184X_PART_CS4231A (11) ! 50: ! 51: /* direct registers: */ ! 52: #define TME_AD184X_REG_IADDR (0) ! 53: #define TME_AD184X_REG_IDATA (1) ! 54: #define TME_AD184X_REG_STATUS (2) ! 55: #define TME_AD184X_REG_PIO (3) ! 56: #define TME_AD184X_SIZ (4) ! 57: ! 58: /* the IADDR register: */ ! 59: #define TME_AD184X_IADDR_INIT (1 << 7) ! 60: #define TME_AD184X_IADDR_MCE (1 << 6) ! 61: #define TME_AD184X_IADDR_TRD (1 << 5) ! 62: #define TME_AD184X_IADDR_IXA (0x0f) ! 63: #define TME_CS423X_IADDR_IXA (0x1f) ! 64: ! 65: /* inputs: */ ! 66: #define TME_AD184X_INPUT_MAIN (0) ! 67: #define TME_AD184X_INPUT_AUX1 (1) ! 68: #define TME_AD184X_INPUT_AUX2 (2) ! 69: ! 70: /* channels: */ ! 71: #define TME_AD184X_CHANNEL_L (0) ! 72: #define TME_AD184X_CHANNEL_R (1) ! 73: #define TME_AD184X_CHANNEL_COUNT (2) ! 74: ! 75: /* the indirect registers: */ ! 76: #define TME_AD184X_IREG_INPUT(input, channel) (((input) * 2) + (channel)) ! 77: #define TME_AD184X_IREG_OUTPUT(channel) (6 + (channel)) ! 78: #define TME_AD184X_IREG_CLOCK_DATA (8) ! 79: #define TME_AD184X_IREG_INTERFACE (9) ! 80: #define TME_AD184X_IREG_PINCONTROL (10) ! 81: #define TME_AD184X_IREG_TEST_INIT (11) ! 82: #define TME_AD184X_IREG_MISC (12) ! 83: #define TME_AD184X_IREG_DIGITALMIX (13) ! 84: #define TME_AD184X_IREG_BASECOUNT_UPPER (14) ! 85: #define TME_AD184X_IREG_BASECOUNT_LOWER (15) ! 86: #define TME_CS423X_IREG_VERSION_ID (25) ! 87: #define TME_CS423X_SIZ_IREG (32) ! 88: ! 89: /* the MISC register: */ ! 90: #define TME_AD184X_MISC_CS423X_MODE2 (1 << 6) ! 91: ! 92: #define TME_AD184X_LOG_HANDLE(ad184x) (&(ad184x)->tme_ad184x_element->tme_element_log_handle) ! 93: ! 94: #define TME_AD184X_BUS_TRANSITION (1) ! 95: ! 96: /* structures: */ ! 97: ! 98: /* the device: */ ! 99: struct tme_ad184x { ! 100: ! 101: /* our simple bus device header: */ ! 102: struct tme_bus_device tme_ad184x_device; ! 103: #define tme_ad184x_element tme_ad184x_device.tme_bus_device_element ! 104: ! 105: /* the mutex: */ ! 106: tme_mutex_t tme_ad184x_mutex; ! 107: ! 108: /* the part: */ ! 109: unsigned int tme_ad184x_part; ! 110: #define TME_AD184X_IS_AD184X(ad184x) ((ad184x)->tme_ad184x_part < TME_AD184X_PART_CS4231) ! 111: #define TME_AD184X_IS_CS423X(ad184x) ((ad184x)->tme_ad184x_part >= TME_AD184X_PART_CS4231) ! 112: #define TME_AD184X_IS_CS4231A(ad184x) ((ad184x)->tme_ad184x_part == TME_AD184X_PART_CS4231A) ! 113: ! 114: /* the IADDR register: */ ! 115: tme_uint8_t tme_ad184x_iaddr; ! 116: ! 117: /* the STATUS register: */ ! 118: tme_uint8_t tme_ad184x_status; ! 119: ! 120: /* the indirect registers: */ ! 121: tme_uint8_t tme_ad184x_ireg[TME_CS423X_SIZ_IREG]; ! 122: }; ! 123: ! 124: /* this resets: */ ! 125: static void ! 126: _tme_ad184x_reset(struct tme_ad184x *ad184x) ! 127: { ! 128: } ! 129: ! 130: /* this enters: */ ! 131: static struct tme_ad184x * ! 132: _tme_ad184x_enter(struct tme_ad184x *ad184x) ! 133: { ! 134: ! 135: /* lock the mutex: */ ! 136: tme_mutex_lock(&ad184x->tme_ad184x_mutex); ! 137: ! 138: return (ad184x); ! 139: } ! 140: #define _tme_ad184x_enter_bus(conn_bus) \ ! 141: ((struct tme_ad184x *) _tme_ad184x_enter((struct tme_ad184x *) (conn_bus)->tme_bus_connection.tme_connection_element->tme_element_private)) ! 142: ! 143: /* this leaves: */ ! 144: #define _tme_ad184x_leave(ad184x) tme_mutex_unlock(&(ad184x)->tme_ad184x_mutex) ! 145: ! 146: /* this busies a generic bus connection: */ ! 147: #define _tme_ad184x_busy_bus(ad184x, conn_index) \ ! 148: ((ad184x)->tme_ad184x_conns[conn_index]) ! 149: ! 150: /* this unbusies a generic bus connection: */ ! 151: #define _tme_ad184x_unbusy_bus(ad184x, conn_bus) \ ! 152: do { } while (/* CONSTCOND */ 0 && (ad184x)->tme_ad184x_element && (conn_bus)->tme_bus_connection.tme_connection_element) ! 153: ! 154: /* this returns the current indirect register: */ ! 155: static unsigned int ! 156: _tme_ad184x_ireg(const struct tme_ad184x *ad184x) ! 157: { ! 158: return (ad184x->tme_ad184x_iaddr ! 159: & ((TME_AD184X_IS_CS423X(ad184x) ! 160: && (ad184x->tme_ad184x_ireg[TME_AD184X_IREG_MISC] ! 161: & TME_AD184X_MISC_CS423X_MODE2)) ! 162: ? TME_CS423X_IADDR_IXA ! 163: : TME_AD184X_IADDR_IXA)); ! 164: } ! 165: ! 166: /* the bus cycle handler: */ ! 167: static void ! 168: _tme_ad184x_cycle(struct tme_bus_connection *master_conn_bus, ! 169: struct tme_bus_cycle *master_cycle, ! 170: tme_uint32_t *_master_fast_cycle_types, ! 171: struct tme_completion *master_completion) ! 172: { ! 173: struct tme_ad184x *ad184x; ! 174: tme_uint32_t address; ! 175: tme_uint8_t value; ! 176: const char *reg; ! 177: tme_uint32_t ireg; ! 178: ! 179: /* enter: */ ! 180: ad184x = _tme_ad184x_enter_bus(master_conn_bus); ! 181: ! 182: /* this must be an eight-bit cycle: */ ! 183: if (master_cycle->tme_bus_cycle_size != sizeof(tme_uint8_t)) { ! 184: abort(); ! 185: } ! 186: ! 187: /* get the address: */ ! 188: address = master_cycle->tme_bus_cycle_address; ! 189: ! 190: /* if this is a write: */ ! 191: if (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 192: ! 193: /* run the bus cycle: */ ! 194: tme_bus_cycle_xfer_reg(master_cycle, ! 195: &value, ! 196: TME_BUS8_LOG2); ! 197: ! 198: /* dispatch on the register: */ ! 199: switch (address) { ! 200: default: assert(FALSE); ! 201: ! 202: case TME_AD184X_REG_IADDR: ! 203: ad184x->tme_ad184x_iaddr ! 204: = ((ad184x->tme_ad184x_iaddr ! 205: & TME_AD184X_IADDR_INIT) ! 206: | (value ! 207: & ~TME_AD184X_IADDR_INIT)); ! 208: reg = "IADDR"; ! 209: break; ! 210: ! 211: case TME_AD184X_REG_IDATA: ! 212: ireg = _tme_ad184x_ireg(ad184x); ! 213: reg = "(IDATA)"; ! 214: ! 215: /* if this is an input or output control: */ ! 216: if (ireg <= TME_AD184X_IREG_OUTPUT(TME_AD184X_CHANNEL_COUNT - 1)) { ! 217: ! 218: /* write the new control: */ ! 219: ad184x->tme_ad184x_ireg[ireg] = value; ! 220: } ! 221: ! 222: /* otherwise, this is another register: */ ! 223: else { ! 224: switch (ireg) { ! 225: ! 226: default: ! 227: /* temporarily, just write any unknown registers: */ ! 228: ad184x->tme_ad184x_ireg[ireg] = value; ! 229: break; ! 230: } ! 231: } ! 232: break; ! 233: ! 234: case TME_AD184X_REG_STATUS: ! 235: reg = "STATUS"; ! 236: break; ! 237: ! 238: case TME_AD184X_REG_PIO: ! 239: reg = "PIO"; ! 240: break; ! 241: } ! 242: ! 243: tme_log(TME_AD184X_LOG_HANDLE(ad184x), 1000, TME_OK, ! 244: (TME_AD184X_LOG_HANDLE(ad184x), ! 245: _("%s <- 0x%02x"), ! 246: reg, ! 247: value)); ! 248: } ! 249: ! 250: /* otherwise, this must be a read: */ ! 251: else { ! 252: assert (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ); ! 253: ! 254: /* dispatch on the register: */ ! 255: switch (address) { ! 256: default: assert(FALSE); ! 257: ! 258: case TME_AD184X_REG_IADDR: ! 259: value = ad184x->tme_ad184x_iaddr; ! 260: reg = "IADDR"; ! 261: break; ! 262: ! 263: case TME_AD184X_REG_IDATA: ! 264: ireg = _tme_ad184x_ireg(ad184x); ! 265: reg = "(IDATA)"; ! 266: ! 267: /* assume that this is a simple read: */ ! 268: value = ad184x->tme_ad184x_ireg[ireg]; ! 269: ! 270: switch (ireg) { ! 271: default: ! 272: break; ! 273: case TME_CS423X_IREG_VERSION_ID: ! 274: value = 0xa0; ! 275: reg = "VERSION_ID"; ! 276: break; ! 277: } ! 278: break; ! 279: ! 280: case TME_AD184X_REG_STATUS: ! 281: value = ad184x->tme_ad184x_status; ! 282: reg = "STATUS"; ! 283: break; ! 284: ! 285: case TME_AD184X_REG_PIO: ! 286: abort(); ! 287: reg = "PIO"; ! 288: break; ! 289: } ! 290: ! 291: /* run the bus cycle: */ ! 292: tme_bus_cycle_xfer_reg(master_cycle, ! 293: &value, ! 294: TME_BUS8_LOG2); ! 295: ! 296: tme_log(TME_AD184X_LOG_HANDLE(ad184x), 1000, TME_OK, ! 297: (TME_AD184X_LOG_HANDLE(ad184x), ! 298: _("%s -> 0x%02x"), ! 299: reg, ! 300: value)); ! 301: } ! 302: ! 303: /* complete the cycle: */ ! 304: master_completion->tme_completion_error = TME_OK; ! 305: tme_memory_barrier(master_completion, sizeof(*master_completion), TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE); ! 306: tme_completion_validate(master_completion); ! 307: *_master_fast_cycle_types = 0; ! 308: ! 309: /* leave: */ ! 310: _tme_ad184x_leave(ad184x); ! 311: } ! 312: ! 313: /* this fills a TLB entry: */ ! 314: static void ! 315: _tme_ad184x_tlb_fill(struct tme_bus_connection *agent_conn_bus, ! 316: struct tme_bus_tlb *tlb, ! 317: tme_bus_addr_t address_wider, ! 318: unsigned int cycle_type) ! 319: { ! 320: ! 321: /* initialize the TLB entry: */ ! 322: tme_bus_tlb_initialize(tlb); ! 323: ! 324: /* this TLB entry covers only this address: */ ! 325: tlb->tme_bus_tlb_addr_first = address_wider; ! 326: tlb->tme_bus_tlb_addr_last = address_wider; ! 327: } ! 328: ! 329: #if TME_AD184X_BUS_TRANSITION ! 330: ! 331: /* this is the bus cycle transition glue: */ ! 332: static int ! 333: _tme_ad184x_cycle_transition(void *_master_conn_bus, ! 334: struct tme_bus_cycle *master_cycle) ! 335: { ! 336: struct tme_completion completion_buffer; ! 337: struct tme_ad184x *ad184x; ! 338: struct tme_bus_connection *master_conn_bus; ! 339: tme_uint32_t master_fast_cycle_types; ! 340: ! 341: tme_completion_init(&completion_buffer); ! 342: ! 343: master_conn_bus = (struct tme_bus_connection *) _master_conn_bus; ! 344: ad184x = (struct tme_ad184x *) master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private; ! 345: _tme_ad184x_cycle(master_conn_bus, ! 346: master_cycle, ! 347: &master_fast_cycle_types, ! 348: &completion_buffer); ! 349: return (completion_buffer.tme_completion_error); ! 350: } ! 351: ! 352: /* this is the TLB fill transition glue: */ ! 353: static int ! 354: _tme_ad184x_tlb_fill_transition(void *_ad184x, ! 355: struct tme_bus_tlb *tlb, ! 356: tme_bus_addr_t address_wider, ! 357: unsigned int cycle_type) ! 358: { ! 359: struct tme_ad184x *ad184x; ! 360: struct tme_bus_connection *agent_conn_bus; ! 361: ! 362: ad184x = (struct tme_ad184x *) _ad184x; ! 363: agent_conn_bus = (struct tme_bus_connection *) ad184x->tme_ad184x_device.tme_bus_device_connection->tme_bus_connection.tme_connection_other; ! 364: ! 365: _tme_ad184x_tlb_fill(agent_conn_bus, ! 366: tlb, ! 367: address_wider, ! 368: cycle_type); ! 369: ! 370: /* we always handle any slow cycles: */ ! 371: tlb->tme_bus_tlb_cycles_ok |= cycle_type; ! 372: tlb->tme_bus_tlb_addr_offset = 0; ! 373: tlb->tme_bus_tlb_addr_shift = 0; ! 374: tlb->tme_bus_tlb_cycle = _tme_ad184x_cycle_transition; ! 375: tlb->tme_bus_tlb_cycle_private = agent_conn_bus; ! 376: assert (tlb->tme_bus_tlb_fault_handler_count == 0); ! 377: ! 378: return (TME_OK); ! 379: } ! 380: #define _tme_ad184x_tlb_fill _tme_ad184x_tlb_fill_transition ! 381: ! 382: #endif /* TME_AD184X_BUS_TRANSITION */ ! 383: ! 384: /* the new ad184x function: */ ! 385: static int ! 386: _tme_ad184x_new(struct tme_element *element, ! 387: const char * const *args, ! 388: const void *extra, ! 389: char **_output, ! 390: unsigned int part) ! 391: { ! 392: struct tme_ad184x *ad184x; ! 393: int arg_i; ! 394: int usage; ! 395: const char *type; ! 396: ! 397: /* check our arguments: */ ! 398: usage = 0; ! 399: arg_i = 1; ! 400: type = NULL; ! 401: for (;;) { ! 402: ! 403: if (0) { ! 404: } ! 405: ! 406: /* if we ran out of arguments: */ ! 407: else if (args[arg_i] == NULL) { ! 408: ! 409: break; ! 410: } ! 411: ! 412: /* otherwise this is a bad argument: */ ! 413: else { ! 414: tme_output_append_error(_output, ! 415: "%s %s, ", ! 416: args[arg_i], ! 417: _("unexpected")); ! 418: usage = TRUE; ! 419: break; ! 420: } ! 421: } ! 422: ! 423: if (usage) { ! 424: tme_output_append_error(_output, ! 425: "%s %s", ! 426: _("usage:"), ! 427: args[0]); ! 428: return (EINVAL); ! 429: } ! 430: ! 431: /* start the ad184x structure: */ ! 432: ad184x = tme_new0(struct tme_ad184x, 1); ! 433: tme_mutex_init(&ad184x->tme_ad184x_mutex); ! 434: ad184x->tme_ad184x_part = part; ! 435: ad184x->tme_ad184x_element = element; ! 436: _tme_ad184x_reset(ad184x); ! 437: ! 438: /* initialize our simple bus device descriptor: */ ! 439: ad184x->tme_ad184x_device.tme_bus_device_tlb_fill = _tme_ad184x_tlb_fill; ! 440: ad184x->tme_ad184x_device.tme_bus_device_address_last = TME_AD184X_SIZ - 1; ! 441: ! 442: /* fill the element: */ ! 443: element->tme_element_private = ad184x; ! 444: element->tme_element_connections_new = tme_bus_device_connections_new; ! 445: ! 446: return (TME_OK); ! 447: } ! 448: ! 449: TME_ELEMENT_X_NEW_DECL(tme_ic_,ad184x,cs4231A) { ! 450: return (_tme_ad184x_new(element, args, extra, _output, TME_AD184X_PART_CS4231A)); ! 451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.