/ 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