Skip to content

Instantly share code, notes, and snippets.

@aditya-r-m
Created July 24, 2022 07:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aditya-r-m/dc006a278274a9615a05587ab965e0df to your computer and use it in GitHub Desktop.
Save aditya-r-m/dc006a278274a9615a05587ab965e0df to your computer and use it in GitHub Desktop.
Custom Trident Z DRAM RGB Turndown
// pieces extracted & trimmed from https://gitlab.com/CalcProgrammer1/OpenRGB
#include <cstring>
#include <iostream>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef int s32;
typedef unsigned short ene_register;
typedef unsigned char ene_dev_id;
#define ENE_APPLY_VAL 0x01 /* Value for Apply Changes Register */
#define ENE_SAVE_VAL 0xAA /* Value for Save Changes */
#define I2C_SMBUS_WRITE 0
#define I2C_SMBUS_BYTE_DATA 2
#define I2C_SMBUS_WORD_DATA 3
enum {
ENE_REG_MODE = 0x8021, /* Mode Selection Register */
ENE_REG_APPLY = 0x80A0, /* Apply Changes Register */
};
s32 i2c_smbus_xfer(int handle, u8 addr, char read_write, u8 command, int size,
union i2c_smbus_data *data) {
struct i2c_smbus_ioctl_data args;
// Tell I2C host which slave address to transfer to
ioctl(handle, I2C_SLAVE, addr);
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
return ioctl(handle, I2C_SMBUS, &args);
}
s32 i2c_smbus_read_byte(int handle, u8 addr) {
i2c_smbus_data data;
if (i2c_smbus_xfer(handle, addr, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data)) {
return -1;
} else {
return data.byte;
}
}
s32 i2c_smbus_write_byte_data(int handle, u8 addr, u8 command, u8 value) {
i2c_smbus_data data;
data.byte = value;
return i2c_smbus_xfer(handle, addr, I2C_SMBUS_WRITE, command,
I2C_SMBUS_BYTE_DATA, &data);
}
s32 i2c_smbus_write_word_data(int handle, u8 addr, u8 command, u16 value) {
i2c_smbus_data data;
data.word = value;
return i2c_smbus_xfer(handle, addr, I2C_SMBUS_WRITE, command,
I2C_SMBUS_WORD_DATA, &data);
}
void ENERegisterWrite(int handle, ene_dev_id dev, ene_register reg,
unsigned char val) {
// Write ENE register
i2c_smbus_write_word_data(handle, dev, 0x00,
((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF));
// Write ENE value
i2c_smbus_write_byte_data(handle, dev, 0x01, val);
}
int main() {
char device_string[1024];
DIR *dir;
char driver_path[512];
struct dirent *ent;
int test_fd;
char path[1024];
char buff[100];
unsigned short pci_device, pci_vendor;
char *ptr;
// Start looking for I2C adapters in /sys/bus/i2c/devices/
strcpy(driver_path, "/sys/bus/i2c/devices/");
dir = opendir(driver_path);
if (dir == NULL) {
return 0;
}
// Loop through all entries in i2c-adapter list
ent = readdir(dir);
if (ent == NULL) {
return 0;
}
while (ent != NULL) {
if (ent->d_type == DT_DIR || ent->d_type == DT_LNK) {
if (strncmp(ent->d_name, "i2c-", 4) == 0) {
strcpy(device_string, driver_path);
strcat(device_string, ent->d_name);
strcat(device_string, "/name");
test_fd = open(device_string, O_RDONLY);
if (test_fd) {
memset(device_string, 0x00, sizeof(device_string));
read(test_fd, device_string, sizeof(device_string));
device_string[strlen(device_string) - 1] = 0x00;
close(test_fd);
// Clear PCI Information
pci_vendor = 0;
pci_device = 0;
// Get device path
strcpy(path, driver_path);
strcat(path, ent->d_name);
if (ent->d_type == DT_LNK) {
ptr = realpath(path, NULL);
if (ptr == NULL)
continue;
strcpy(path, ptr);
strcat(path, "/..");
free(ptr);
} else {
strcat(path, "/device");
}
ptr = path + strlen(path);
// Get PCI Vendor
strcpy(ptr, "/vendor");
test_fd = open(path, O_RDONLY);
if (test_fd >= 0) {
memset(buff, 0x00, sizeof(buff));
read(test_fd, buff, sizeof(buff));
buff[strlen(buff) - 1] = 0x00;
pci_vendor = strtoul(buff, NULL, 16);
close(test_fd);
}
// Get PCI Device
strcpy(ptr, "/device");
test_fd = open(path, O_RDONLY);
if (test_fd >= 0) {
memset(buff, 0x00, sizeof(buff));
read(test_fd, buff, sizeof(buff));
buff[strlen(buff) - 1] = 0x00;
pci_device = strtoul(buff, NULL, 16);
close(test_fd);
}
strcpy(device_string, "/dev/");
strcat(device_string, ent->d_name);
test_fd = open(device_string, O_RDWR);
if (test_fd < 0) {
ent = readdir(dir);
} else {
if (pci_vendor == 0x1022 && pci_device == 0x790B) {
if (i2c_smbus_read_byte(test_fd, 0x77) > -1) {
ENERegisterWrite(test_fd, 0x77, ENE_REG_MODE, 0);
ENERegisterWrite(test_fd, 0x77, ENE_REG_APPLY, ENE_APPLY_VAL);
}
}
}
}
}
}
ent = readdir(dir);
}
closedir(dir);
return 0;
}
@PsY4
Copy link

PsY4 commented Nov 7, 2023

Great job on this ! Thx a lot, I managed to turn off the LEDs on four G.Skill Trident Z RGB DDR4-4000 on my NAS !

Just adding notes to help others :

You NEED to change the vendor and device test on line 172 to match your motherboard i2c bridge.
This code uses an unknown AMD board so it uses 0x1022 / 0x790B
On my Intel Asrock B660M board, I had to use 0x8086 / 0x7AA3

To find out your vendor and device id, you must use:
cat /sys/bus/i2c/devices/i2c-*/device/vendor
cat /sys/bus/i2c/devices/i2c-*/device/device

Edit line 172 with these numbers.
Then, just compile the file using G++ :
g++ -o ledoff crgb.cc

And run it :
./ledoff

@aditya-r-m
Copy link
Author

I'm glad this was useful @PsY4 :) Thanks a lot for the added pointers.

@Trogious
Copy link

Trogious commented Jan 6, 2024

I had to do some changes for this to work on my setup:

  • MSI z790 Carbon WIFI
  • 4 pieces of: F5-7200J3445G16GX2-TZ5RS

changed code:
https://github.com/Trogious/trident-z5-rgb-off

@aditya-r-m
Copy link
Author

Thank you for the added pointer, @Trogious!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment