/ A1-board-selector-CCR.c
A1-board-selector-CCR.c
1 /* 2 * board selector support for TCA9535 used in Bitmine's CoinCraft Desk 3 * 4 * Copyright 2014 Zefir Kurtisi <zefir.kurtisi@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the Free 8 * Software Foundation; either version 3 of the License, or (at your option) 9 * any later version. See COPYING for more details. 10 */ 11 12 13 #include "miner.h" 14 15 #include "A1-board-selector.h" 16 #include "i2c-context.h" 17 18 19 static struct board_selector ccr_selector; 20 21 static struct i2c_ctx *U1_tca9548; 22 static struct i2c_ctx *U3_tca9535; 23 static struct i2c_ctx *U4_tca9535; 24 static uint8_t active_chain; 25 static pthread_mutex_t lock; 26 27 struct chain_mapping { 28 uint8_t chain_id; 29 uint8_t U1; 30 uint8_t U3p0; 31 uint8_t U3p1; 32 }; 33 34 static const struct chain_mapping chain_mapping[CCR_MAX_CHAINS] = { 35 { 0, 0x01, 0x01, 0x00, }, 36 { 1, 0x01, 0x00, 0x80, }, 37 { 2, 0x02, 0x02, 0x00, }, 38 { 3, 0x02, 0x00, 0x40, }, 39 { 4, 0x04, 0x04, 0x00, }, 40 { 5, 0x04, 0x00, 0x20, }, 41 { 6, 0x08, 0x08, 0x00, }, 42 { 7, 0x08, 0x00, 0x10, }, 43 { 8, 0x10, 0x10, 0x00, }, 44 { 9, 0x10, 0x00, 0x08, }, 45 { 10, 0x20, 0x20, 0x00, }, 46 { 11, 0x20, 0x00, 0x04, }, 47 { 12, 0x40, 0x40, 0x00, }, 48 { 13, 0x40, 0x00, 0x02, }, 49 { 14, 0x80, 0x80, 0x00, }, 50 { 15, 0x80, 0x00, 0x01, }, 51 }; 52 53 static void ccr_unlock(void) 54 { 55 mutex_unlock(&lock); 56 } 57 58 static void ccr_exit(void) 59 { 60 if (U1_tca9548 != NULL) 61 U1_tca9548->exit(U1_tca9548); 62 if (U3_tca9535 != NULL) 63 U3_tca9535->exit(U3_tca9535); 64 if (U4_tca9535 != NULL) 65 U4_tca9535->exit(U4_tca9535); 66 } 67 68 69 extern struct board_selector *ccr_board_selector_init(void) 70 { 71 mutex_init(&lock); 72 applog(LOG_INFO, "ccr_board_selector_init()"); 73 74 /* detect all i2c slaves */ 75 U1_tca9548 = i2c_slave_open(I2C_BUS, 0x70); 76 U3_tca9535 = i2c_slave_open(I2C_BUS, 0x23); 77 U4_tca9535 = i2c_slave_open(I2C_BUS, 0x22); 78 if (U1_tca9548 == NULL || U3_tca9535 == NULL || U4_tca9535 == NULL) 79 goto fail; 80 81 /* init I2C multiplexer */ 82 bool res = U1_tca9548->write(U1_tca9548, 0x00, 0x00) && 83 /* init reset selector */ 84 U3_tca9535->write(U3_tca9535, 0x06, 0x00) && 85 U3_tca9535->write(U3_tca9535, 0x07, 0x00) && 86 U3_tca9535->write(U3_tca9535, 0x02, 0x00) && 87 U3_tca9535->write(U3_tca9535, 0x03, 0x00) && 88 /* init chain selector */ 89 U4_tca9535->write(U4_tca9535, 0x06, 0x00) && 90 U4_tca9535->write(U4_tca9535, 0x07, 0x00) && 91 U4_tca9535->write(U4_tca9535, 0x02, 0x00) && 92 U4_tca9535->write(U4_tca9535, 0x03, 0x00); 93 94 if (!res) 95 goto fail; 96 97 return &ccr_selector; 98 99 fail: 100 ccr_exit(); 101 return NULL; 102 } 103 104 static bool ccr_select(uint8_t chain) 105 { 106 if (chain >= CCR_MAX_CHAINS) 107 return false; 108 109 mutex_lock(&lock); 110 if (active_chain == chain) 111 return true; 112 113 active_chain = chain; 114 const struct chain_mapping *cm = &chain_mapping[chain]; 115 116 if (!U1_tca9548->write(U1_tca9548, cm->U1, cm->U1)) 117 return false; 118 119 if (!U4_tca9535->write(U4_tca9535, 0x02, cm->U3p0) || 120 !U4_tca9535->write(U4_tca9535, 0x03, cm->U3p1)) 121 return false; 122 123 /* sanity check: ensure i2c command has been written before we leave */ 124 uint8_t tmp; 125 if (!U4_tca9535->read(U4_tca9535, 0x02, &tmp) || tmp != cm->U3p0) { 126 applog(LOG_ERR, "ccr_select: wrote 0x%02x, read 0x%02x", 127 cm->U3p0, tmp); 128 } 129 applog(LOG_DEBUG, "selected chain %d", chain); 130 return true; 131 } 132 133 static bool __ccr_board_selector_reset(uint8_t p0, uint8_t p1) 134 { 135 if (!U3_tca9535->write(U3_tca9535, 0x02, p0) || 136 !U3_tca9535->write(U3_tca9535, 0x03, p1)) 137 return false; 138 cgsleep_ms(RESET_LOW_TIME_MS); 139 if (!U3_tca9535->write(U3_tca9535, 0x02, 0x00) || 140 !U3_tca9535->write(U3_tca9535, 0x03, 0x00)) 141 return false; 142 cgsleep_ms(RESET_HI_TIME_MS); 143 return true; 144 } 145 // we assume we are already holding the mutex 146 static bool ccr_reset(void) 147 { 148 const struct chain_mapping *cm = &chain_mapping[active_chain]; 149 applog(LOG_DEBUG, "resetting chain %d", cm->chain_id); 150 bool retval = __ccr_board_selector_reset(cm->U3p0, cm->U3p1); 151 return retval; 152 } 153 154 static bool ccr_reset_all(void) 155 { 156 mutex_lock(&lock); 157 bool retval = __ccr_board_selector_reset(0xff, 0xff); 158 mutex_unlock(&lock); 159 return retval; 160 } 161 162 static uint8_t ccr_get_temp(uint8_t sensor_id) 163 { 164 if ((active_chain & 1) != 0 || sensor_id != 0) 165 return 0; 166 167 struct i2c_ctx *U7 = i2c_slave_open(I2C_BUS, 0x4c); 168 if (U7 == NULL) 169 return 0; 170 171 uint8_t retval = 0; 172 if (!U7->read(U7, 0, &retval)) 173 retval = 0; 174 U7->exit(U7); 175 return retval; 176 } 177 178 static struct board_selector ccr_selector = { 179 .select = ccr_select, 180 .release = ccr_unlock, 181 .exit = ccr_exit, 182 .reset = ccr_reset, 183 .reset_all = ccr_reset_all, 184 .get_temp = ccr_get_temp, 185 }; 186