/ A1-board-selector-CCD.c
A1-board-selector-CCD.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 <sys/ioctl.h>
 14  #include <errno.h>
 15  #include <string.h>
 16  #include <stdio.h>
 17  #include <stdlib.h>
 18  #include <unistd.h>
 19  #include <linux/i2c.h>
 20  #include <linux/i2c-dev.h>
 21  
 22  #include <stdint.h>
 23  #include <stdbool.h>
 24  #include <fcntl.h>
 25  
 26  #include "miner.h"
 27  
 28  #include "A1-board-selector.h"
 29  #include "i2c-context.h"
 30  
 31  static struct board_selector ccd_selector;
 32  
 33  struct i2c_ctx *U1_tca9535;
 34  uint8_t chain_mask = 0xff;
 35  uint8_t active_chain = 255;
 36  pthread_mutex_t lock;
 37  
 38  
 39  #define UNUSED_BITS 0xe0
 40  
 41  static void ccd_unlock(void)
 42  {
 43  	mutex_unlock(&lock);
 44  }
 45  
 46  static void ccd_exit(void)
 47  {
 48  	if (U1_tca9535 != NULL)
 49  		U1_tca9535->exit(U1_tca9535);
 50  }
 51  uint8_t retval = 0;
 52  
 53  extern struct board_selector *ccd_board_selector_init(void)
 54  {
 55  	mutex_init(&lock);
 56  	U1_tca9535 = i2c_slave_open(I2C_BUS, 0x27);
 57  	if (U1_tca9535 == NULL)
 58  		return NULL;
 59  	bool retval =	U1_tca9535->write(U1_tca9535, 0x06, 0xe0) &&
 60  			U1_tca9535->write(U1_tca9535, 0x07, 0xe0) &&
 61  			U1_tca9535->write(U1_tca9535, 0x02, 0x1f) &&
 62  			U1_tca9535->write(U1_tca9535, 0x03, 0x00);
 63  	if (retval)
 64  		return &ccd_selector;
 65  	ccd_exit();
 66  	return NULL;
 67  }
 68  
 69  static bool ccd_select(uint8_t chain)
 70  {
 71  	if (chain >= CCD_MAX_CHAINS)
 72  		return false;
 73  
 74  	mutex_lock(&lock);
 75  	if (active_chain == chain)
 76  		return true;
 77  
 78  	active_chain = chain;
 79  	chain_mask = 1 << active_chain;
 80  	return U1_tca9535->write(U1_tca9535, 0x02, ~chain_mask);
 81  }
 82  
 83  static bool __ccd_board_selector_reset(uint8_t mask)
 84  {
 85  	if (!U1_tca9535->write(U1_tca9535, 0x03, mask))
 86  		return false;
 87  	cgsleep_ms(RESET_LOW_TIME_MS);
 88  	if (!U1_tca9535->write(U1_tca9535, 0x03, 0x00))
 89  		return false;
 90  	cgsleep_ms(RESET_HI_TIME_MS);
 91  	return true;
 92  }
 93  // we assume we are already holding the mutex
 94  static bool ccd_reset(void)
 95  {
 96  	return __ccd_board_selector_reset(chain_mask);
 97  }
 98  
 99  static bool ccd_reset_all(void)
100  {
101  	mutex_lock(&lock);
102  	bool retval = __ccd_board_selector_reset(0xff & ~UNUSED_BITS);
103  	mutex_unlock(&lock);
104  	return retval;
105  }
106  
107  
108  static struct board_selector ccd_selector = {
109  	.select = ccd_select,
110  	.release = ccd_unlock,
111  	.exit = ccd_exit,
112  	.reset = ccd_reset,
113  	.reset_all = ccd_reset_all,
114  	/* don't have a temp sensor dedicated to chain */
115  	.get_temp = dummy_get_temp,
116  };
117