/ A1-trimpot-mcp4x.c
A1-trimpot-mcp4x.c
  1  /*
  2   * support for MCP46x digital trimpot used in Bitmine's products
  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 <assert.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  #include <sys/ioctl.h>
 22  
 23  #include <stdint.h>
 24  #include <stdbool.h>
 25  #include <fcntl.h>
 26  
 27  #include "miner.h"
 28  
 29  #include "A1-trimpot-mcp4x.h"
 30  
 31  
 32  static bool mcp4x_check_status(int file)
 33  {
 34  	union i2c_smbus_data data;
 35  	struct i2c_smbus_ioctl_data args;
 36  
 37  	args.read_write = I2C_SMBUS_READ;
 38  	args.command = ((5 & 0x0f) << 4) | 0x0c;
 39  	args.size = I2C_SMBUS_WORD_DATA;
 40  	args.data = &data;
 41  
 42  	return ioctl(file, I2C_SMBUS, &args) >= 0;
 43  }
 44  
 45  static uint16_t mcp4x_get_wiper(struct mcp4x *me, uint8_t id)
 46  {
 47  	assert(id < 2);
 48  	union i2c_smbus_data data;
 49  	struct i2c_smbus_ioctl_data args;
 50  
 51  	args.read_write = I2C_SMBUS_READ;
 52  	args.command = ((id & 0x0f) << 4) | 0x0c;
 53  	args.size = I2C_SMBUS_WORD_DATA;
 54  	args.data = &data;
 55  
 56  	if (ioctl(me->file, I2C_SMBUS, &args) < 0) {
 57  		applog(LOG_ERR, "Failed to read id %d: %s\n", id,
 58  		       strerror(errno));
 59  		return 0xffff;
 60  	}
 61  	return htobe16(data.word & 0xffff);
 62  }
 63  
 64  static bool mcp4x_set_wiper(struct mcp4x *me, uint8_t id, uint16_t w)
 65  {
 66  	assert(id < 2);
 67  	union i2c_smbus_data data;
 68  	data.word = w;
 69  
 70  	struct i2c_smbus_ioctl_data args;
 71  
 72  	args.read_write = I2C_SMBUS_WRITE;
 73  	args.command = (id & 0x0f) << 4;
 74  	args.size = I2C_SMBUS_WORD_DATA;
 75  	args.data = &data;
 76  
 77  	if (ioctl(me->file, I2C_SMBUS, &args) < 0) {
 78  		applog(LOG_ERR, "Failed to read id %d: %s\n", id,
 79  		       strerror(errno));
 80  		return false;
 81  	}
 82  	return me->get_wiper(me, id) == w;
 83  }
 84  
 85  void mcp4x_exit(struct mcp4x *me)
 86  {
 87  	close(me->file);
 88  	free(me);
 89  }
 90  
 91  struct mcp4x *mcp4x_init(uint8_t addr)
 92  {
 93  	struct mcp4x *me;
 94  	int file = open("/dev/i2c-1", O_RDWR);
 95  	if (file < 0) {
 96  		applog(LOG_INFO, "Failed to open i2c-1: %s\n", strerror(errno));
 97  		return NULL;
 98  	}
 99  
100  	if (ioctl(file, I2C_SLAVE, addr) < 0)
101  		return NULL;
102  
103  	if (!mcp4x_check_status(file))
104  		return NULL;
105  
106  	me = malloc(sizeof(*me));
107  	assert(me != NULL);
108  
109  	me->addr = addr;
110  	me->file = file;
111  	me->exit = mcp4x_exit;
112  	me->get_wiper = mcp4x_get_wiper;
113  	me->set_wiper = mcp4x_set_wiper;
114  	return me;
115  }
116