@AreYouLoco I was about to reply but then saw that you have it working. Not sure if my code will help you further, but here it is:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <hw/i2c.h>
static int i2c_fd;
static int verbose;
static bool
send_recv(
uint32_t const addr,
uint8_t const * const send,
uint32_t const sendlen,
uint8_t * const recv
)
{
struct {
i2c_sendrecv_t hdr;
uint8_t data[8];
} msg = {
.hdr = {
.slave = {
.addr = addr,
.fmt = I2C_ADDRFMT_7BIT
},
.send_len = sendlen,
.recv_len = 1,
.stop = 1
}
};
memcpy(msg.data, send, sendlen);
int const rc = devctl(i2c_fd, DCMD_I2C_SENDRECV, &msg, sizeof(msg), NULL);
if (rc == -1) {
perror("devctl");
return false;
}
if (verbose) {
fprintf(stderr, "%.2x %.2x %.2x\n", addr, send[0], msg.data[0]);
}
if (recv) {
*recv = msg.data[0];
}
return true;
}
static uint8_t
amc6821_read_reg(uint8_t const reg)
{
// Switch to channel 1.
uint8_t channel = 9;
if (!send_recv(0x77, &channel, 1, NULL)) {
return 0;
}
// Read register.
uint8_t value;
if (!send_recv(0x18, ®, 1, &value)) {
return 0;
}
return value;
}
static void
amc6821_write_reg(uint8_t const reg, uint8_t const value)
{
// Switch to channel 1.
uint8_t channel = 9;
if (!send_recv(0x77, &channel, 1, NULL)) {
return;
}
// Write register.
uint8_t data[2] = { reg, value };
if (!send_recv(0x18, data, 2, NULL)) {
return;
}
}
int
main(int argc, char **argv)
{
int duty = -1;
for (;;) {
int const opt = getopt(argc, argv, "d:v");
if (opt == 'd') {
duty = strtol(optarg, NULL, 0);
if ((duty < 0) || (duty > 100)) {
fprintf(stderr, "Bad duty cycle value: %d\n", duty);
}
} else if (opt == 'v') {
verbose++;
} else {
break;
}
}
i2c_fd = open("/dev/i2c0", O_RDWR);
if (i2c_fd == -1) {
perror("open");
return EXIT_FAILURE;
}
// Enable fan speed monitoring and set software DCY control.
uint8_t conf1 = amc6821_read_reg(0x0);
conf1 |= 1 << 0;
conf1 &= ~((1 << 6) | (1 << 5));
amc6821_write_reg(0x0, conf1);
uint8_t conf2 = amc6821_read_reg(0x1);
conf2 |= 1 << 2;
amc6821_write_reg(0x1, conf2);
// Write a duty cycle value.
if (duty != -1) {
duty = (duty * 255) / 100;
amc6821_write_reg(0x22, duty);
}
for (;;) {
uint32_t tach = amc6821_read_reg(0x8);
tach += (uint32_t)amc6821_read_reg(0x9) << 8;
int8_t temp = (int8_t)amc6821_read_reg(0xa);
printf("temp=%d speed=%u\n", temp, (6000000 / tach));
sleep(1);
}
return EXIT_SUCCESS;
}
You just need to implement send_recv()
for your system.
–Elad