blob: 3cb1cbccdd176b73d8da5d676daefb713276a0e4 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// lib_smogcheck.c: C code to make direct I2C calls using ioctl().
//
// Adapted and modified from:
// http://www.mjmwired.net/kernel/Documentation/i2c/dev-interface
#include "lib/lib_smogcheck.h"
#include <errno.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define arraysize(x) (sizeof(x) / sizeof(x[0]))
// Opens a device file for I/O operations.
//
// Args:
// adapter_nr: an integer, adapater's number address.
//
// Returns:
// a file descriptor (non-negative integer), ready to use. Or -1 if error.
int GetDeviceFile(int adapter_nr) {
int file;
char filename[20] = {0};
snprintf(filename, arraysize(filename) - 1, "/dev/i2c-%d", adapter_nr);
printf("Attempt to open device %s\n", filename);
file = open(filename, O_RDWR);
if (file < 0) {
printf("Error opening file %d: %s\n", errno, strerror(errno));
return -1;
}
printf("Successfully opened device %s\n", filename);
return file;
}
// Sets I2C device address to communicate with.
//
// Args:
// fd: an integer, open device file descriptor.
// addr: an integer, I2C slave address to set.
//
// Returns:
// 0 if success, -1 if error.
int SetSlaveAddress(int fd, int addr) {
if (fd < 0) {
printf("Error: invalid file descriptor %d. Expect integer >= 0\n", fd);
return -1;
} else if (addr < 0x08 || addr > 0x77) {
printf(
"Error: invalid 7-bit I2C slave address %d. Expect range is "
"an integer in [8, 112]\n",
addr);
return -1;
}
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
printf("Error communicating to slave address: %s\n", strerror(errno));
return -1;
}
return 0;
}
// Precondition checks.
//
// Args:
// fd: a non-negative integer, open device file descriptor.
//
// Returns:
// ret: a boolean, true if fd is non-negative and false otherwise.
bool PreconditionCheck(int fd) {
if (fd < 0) {
printf("Error: invalid file descriptor %d. Expect integer >= 0\n", fd);
return false;
}
return true;
}
// Writes a byte to specified register address.
//
// Args:
// fd: an integer, open device file descriptor.
// reg: an 8-bit unsigned integer, non-negative register number.
// byte_val: an 8-bit unsigned integer, value to write.
//
// Returns:
// 0 if success, -1 if error.
int WriteByte(int fd, uint8_t reg, uint8_t byte_val) {
union i2c_smbus_data data;
data.byte = byte_val;
struct i2c_smbus_ioctl_data args;
args.read_write = I2C_SMBUS_WRITE;
args.command = reg;
args.size = I2C_SMBUS_BYTE_DATA;
args.data = &data;
if (PreconditionCheck(fd) != true) {
return -1;
}
if (ioctl(fd, I2C_SMBUS, &args)) {
printf("Error writing to register: %s\n", strerror(errno));
return -1;
}
printf("Wrote to register %d: 0x%x\n", reg, byte_val);
return 0;
}
// Reads a byte value from a specified register address.
//
// Args:
// fd: an integer, open device file descriptor.
// reg: an 8-bit unsigned integer, non-negative register number.
//
// Returns:
// byte value read if success, -1 if error.
int ReadByte(int fd, uint8_t reg) {
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data args;
args.read_write = I2C_SMBUS_READ;
args.command = reg;
args.size = I2C_SMBUS_BYTE_DATA;
args.data = &data;
if (PreconditionCheck(fd) != true) {
return -1;
}
if (ioctl(fd, I2C_SMBUS, &args)) {
printf("Error reading from bus: %s\n", strerror(errno));
return -1;
}
printf("Read back from bus: 0x%x\n", data.byte);
return data.byte;
}
// Writes a word to specified register address.
//
// Args:
// fd: an integer, open device file descriptor.
// reg: an 8-bit unsigned integer, register number.
// word_val: a 16-bit unsigned integer, value to write.
//
// Returns:
// 0 if success, -1 if error.
int WriteWord(int fd, uint8_t reg, uint16_t word_val) {
union i2c_smbus_data data;
data.word = word_val;
struct i2c_smbus_ioctl_data args;
args.read_write = I2C_SMBUS_WRITE;
args.command = reg;
args.size = I2C_SMBUS_WORD_DATA;
args.data = &data;
if (PreconditionCheck(fd) != true) {
return -1;
}
if (ioctl(fd, I2C_SMBUS, &args)) {
printf("Error writing to register: %s\n", strerror(errno));
return -1;
}
printf("Wrote to register %d: 0x%x\n", reg, word_val);
return 0;
}
// Reads a word from a specified register address.
//
// Args:
// fd: an integer, open device file descriptor.
// reg: an 8-bit unsigned integer, register number.
//
// Returns:
// word value read if success, -1 if error.
int ReadWord(int fd, uint8_t reg) {
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data args;
args.read_write = I2C_SMBUS_READ;
args.command = reg;
args.size = I2C_SMBUS_WORD_DATA;
args.data = &data;
if (PreconditionCheck(fd) != true) {
return -1;
}
if (ioctl(fd, I2C_SMBUS, &args)) {
printf("Error reading from bus: %s\n", strerror(errno));
return -1;
}
printf("Read back from bus: 0x%x\n", data.word);
return data.word;
}