ODROID-XU3: add Hardkernel INA231 driver

Change-Id: I27f0fd585e58da786d0e34dfcf35fb6b9c1be36b
This commit is contained in:
charles.park
2017-01-19 10:51:28 +09:00
parent 82c5d3a770
commit 9f45809887
12 changed files with 1064 additions and 20 deletions

65
arch/arm/boot/dts/exynos5422-odroidxu3.dts Normal file → Executable file
View File

@@ -20,35 +20,60 @@
compatible = "hardkernel,odroid-xu3", "samsung,exynos5800", "samsung,exynos5";
};
/*
i2c0 INA231 Sensors
- drivers/hardkernel/ina231.h
config = INA231_CONFIG(VSH_CT(eVSH_CT_8244uS) | \
VBUS_CT(eVBUS_CT_8244uS) | \
AVG_BIT(eAVG_16) | \
eSHUNT_BUS_VOLT_CONTINUOUS),
update_period = CONVERSION_DELAY(eVSH_CON_8244uS, eVBUS_CON_8244uS, eAVG_CON_16),
*/
&i2c_0 {
status = "okay";
/* A15 cluster: VDD_ARM */
ina231@40 {
compatible = "ti,ina231";
clock-frequency = <400000>;
ina231@40 {
compatible = "hardkernel,INA231";
reg = <0x40>;
shunt-resistor = <10000>;
sensor-name = "sensor_arm";
enable = <0>;
max_A = <9>;
shunt_R_mohm = <10>;
config = <0x45FF>;
update_period = <263808>;
};
/* memory: VDD_MEM */
ina231@41 {
compatible = "ti,ina231";
ina231@41 {
compatible = "hardkernel,INA231";
reg = <0x41>;
shunt-resistor = <10000>;
sensor-name = "sensor_mem";
enable = <0>;
max_A = <3>;
shunt_R_mohm = <10>;
config = <0x45FF>;
update_period = <263808>;
};
/* GPU: VDD_G3D */
ina231@44 {
compatible = "ti,ina231";
ina231@44 {
compatible = "hardkernel,INA231";
reg = <0x44>;
shunt-resistor = <10000>;
sensor-name = "sensor_g3d";
enable = <0>;
max_A = <5>;
shunt_R_mohm = <10>;
config = <0x45FF>;
update_period = <263808>;
};
/* A7 cluster: VDD_KFC */
ina231@45 {
compatible = "ti,ina231";
ina231@45 {
compatible = "hardkernel,INA231";
reg = <0x45>;
shunt-resistor = <10000>;
sensor-name = "sensor_kfc";
enable = <0>;
max_A = <2>;
shunt_R_mohm = <10>;
config = <0x45FF>;
update_period = <263808>;
};
};

View File

@@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
# Hardkernel Specific drivers
source "drivers/hardkernel/Kconfig"
endmenu

View File

@@ -173,3 +173,6 @@ obj-$(CONFIG_STM) += hwtracing/stm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_NVMEM) += nvmem/
obj-$(CONFIG_FPGA) += fpga/
# Hardkernel Specific drivers
obj-y += hardkernel/

10
drivers/hardkernel/Kconfig Executable file
View File

@@ -0,0 +1,10 @@
menu "ODROID Specific Hardware"
config ODROID_EXYNOS5_SP
tristate "Enable the INA231 Sensor on ODROID-EXYNOS5"
depends on I2C && ARCH_EXYNOS5
default n
---help---
Enables the INA231 Sensor on ODROID-EXYNOS5
endmenu

2
drivers/hardkernel/Makefile Executable file
View File

@@ -0,0 +1,2 @@
obj-$(CONFIG_ODROID_EXYNOS5_SP) += ina231-sensor.o
ina231-sensor-y := ina231-misc.o ina231-sysfs.o ina231-i2c.o

341
drivers/hardkernel/ina231-i2c.c Executable file
View File

@@ -0,0 +1,341 @@
//[*]------------------------------------------------------------------------[*]
//
//
// I2C INA231(Sensor) driver
// 2013.07.17
//
//
//[*]------------------------------------------------------------------------[*]
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
//[*]------------------------------------------------------------------------[*]
#include "ina231.h"
#include "ina231-misc.h"
#include "ina231-sysfs.h"
//#define DEBUG_INA231
//[*]------------------------------------------------------------------------[*]
//
// function prototype
//
//[*]------------------------------------------------------------------------[*]
static void __exit ina231_i2c_exit (void);
static int __init ina231_i2c_init (void);
static int ina231_i2c_remove (struct i2c_client *client);
static int ina231_i2c_probe (struct i2c_client *client, const struct i2c_device_id *id);
static void ina231_work (struct work_struct *work);
int ina231_i2c_read (struct i2c_client *client, unsigned char cmd);
int ina231_i2c_write (struct i2c_client *client, unsigned char cmd, unsigned short data);
void ina231_i2c_enable (struct ina231_sensor *sensor);
static enum hrtimer_restart ina231_timer (struct hrtimer *timer);
//[*]------------------------------------------------------------------------[*]
int ina231_i2c_read(struct i2c_client *client, unsigned char cmd)
{
struct i2c_msg msg[2];
int ret;
unsigned char buf[2];
memset(msg, 0x00, sizeof(msg));
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &cmd;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 2;
msg[1].buf = &buf[0];
if ((ret = i2c_transfer(client->adapter, msg, 2)) != 2) {
dev_err(&client->dev, "I2C read error: (%d) reg: 0x%X \n", ret, cmd);
return -EIO;
}
ret = ((buf[0] << 8) | buf[1]) & 0xFFFF;
return ret;
}
//[*]------------------------------------------------------------------------[*]
int ina231_i2c_write(struct i2c_client *client, unsigned char cmd, unsigned short data)
{
int ret;
unsigned char block_data[3];
memset(block_data, 0x00, sizeof(block_data));
block_data[0] = cmd;
block_data[1] = (data >> 8) & 0xFF;
block_data[2] = (data ) & 0xFF;
if ((ret = i2c_master_send(client, block_data, 3)) < 0) {
dev_err(&client->dev, "I2C write error: (%d) reg: 0x%X \n", ret, cmd);
return ret;
}
return ret;
}
//[*]------------------------------------------------------------------------[*]
void ina231_i2c_enable(struct ina231_sensor *sensor)
{
hrtimer_start(&sensor->timer,
ktime_set(sensor->timer_sec, sensor->timer_nsec),
HRTIMER_MODE_REL);
}
//[*]------------------------------------------------------------------------[*]
static void ina231_work (struct work_struct *work)
{
struct ina231_sensor *sensor = container_of(work, struct ina231_sensor, work);
if (sensor->pd->enable) {
sensor->reg_bus_volt = ina231_i2c_read(sensor->client, REG_BUS_VOLT);
sensor->reg_current = ina231_i2c_read(sensor->client, REG_CURRENT );
mutex_lock(&sensor->mutex);
sensor->cur_uV = sensor->reg_bus_volt * FIX_uV_LSB;
sensor->cur_uA = sensor->reg_current * sensor->cur_lsb_uA;
sensor->cur_uW = (sensor->cur_uV / 1000 ) * (sensor->cur_uA / 1000);
if ((sensor->cur_uV > sensor->max_uV) || (sensor->cur_uA > sensor->cur_uA)) {
sensor->max_uV = sensor->cur_uV;
sensor->max_uA = sensor->cur_uA;
sensor->max_uW = sensor->cur_uW;
}
mutex_unlock(&sensor->mutex);
}
else {
sensor->cur_uV = 0;
sensor->cur_uA = 0;
sensor->cur_uW = 0;
}
#if defined(DEBUG_INA231)
printk("%s : BUS Voltage = %06d uV, %1d.%06d V\n",
sensor->pd->name, sensor->cur_uV,
sensor->cur_uV/1000000,
sensor->cur_uV%1000000);
printk("%s : Curent = %06d uA, %1d.%06d A\n",
sensor->pd->name, sensor->cur_uA,
sensor->cur_uA/1000000,
sensor->cur_uA%1000000);
printk("%s : Powert = %06d uW, %1d.%06d W\n",
sensor->pd->name, sensor->cur_uW,
sensor->cur_uW/1000000,
sensor->cur_uW%1000000);
#endif
}
//[*]------------------------------------------------------------------------[*]
static enum hrtimer_restart ina231_timer(struct hrtimer *timer)
{
struct ina231_sensor *sensor = container_of(timer, struct ina231_sensor, timer);
queue_work(sensor->wq, &sensor->work);
if (sensor->pd->enable) ina231_i2c_enable(sensor);
return HRTIMER_NORESTART;
}
//[*]------------------------------------------------------------------------[*]
#ifdef CONFIG_OF
static int ina231_i2c_dt_parse(struct i2c_client *client, struct ina231_sensor *sensor)
{
struct device_node *sensor_np = client->dev.of_node;
const char *sensor_name;
unsigned int rdata;
if (!(sensor->pd = devm_kzalloc(&client->dev, sizeof(struct ina231_pd),
GFP_KERNEL))) {
dev_err(&client->dev, "INA231 Sensor platform data struct malloc error!\n");
return -ENOMEM;
}
if (of_property_read_string(sensor_np, "sensor-name", &sensor_name))
return -1;
sensor->pd->name = (unsigned char *)sensor_name;
if (of_property_read_u32(sensor_np, "enable", &rdata))
return -1;
sensor->pd->enable = rdata;
if (of_property_read_u32(sensor_np, "max_A", &rdata))
return -1;
sensor->pd->max_A = rdata;
if (of_property_read_u32(sensor_np, "shunt_R_mohm", &rdata))
return -1;
sensor->pd->shunt_R_mohm = rdata;
if (of_property_read_u32(sensor_np, "config", &rdata))
return -1;
sensor->pd->config = rdata;
if (of_property_read_u32(sensor_np, "update_period", &rdata))
return -1;
sensor->pd->update_period = rdata;
return 0;
}
#else // CONFIG_OF
static int ina231_i2c_dt_parse(struct i2c_client *client, struct ina231_sensor *sensor)
{
return 0;
}
#endif
//[*]------------------------------------------------------------------------[*]
static int ina231_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int rc = 0;
struct ina231_sensor *sensor;
if (!(sensor = devm_kzalloc(&client->dev, sizeof(struct ina231_sensor),
GFP_KERNEL))) {
dev_err(&client->dev, "INA231 Sensor struct malloc error!\n");
return -ENOMEM;
}
// mutex init
mutex_init(&sensor->mutex);
sensor->client = client;
if (client->dev.of_node) {
if(ina231_i2c_dt_parse(client, sensor) < 0)
goto out;
}
else {
sensor->pd = client->dev.platform_data;
}
i2c_set_clientdata(client, sensor);
// Calculate current lsb value
sensor->cur_lsb_uA = sensor->pd->max_A * 1000000 / 32768;
// Calculate register value
sensor->reg_calibration = 5120000 / (sensor->cur_lsb_uA * sensor->pd->shunt_R_mohm);
if ((rc = ina231_i2c_write(sensor->client, REG_CONFIG, sensor->pd->config)) < 0)
goto out;
if ((rc = ina231_i2c_write(sensor->client, REG_CALIBRATION, sensor->reg_calibration)) < 0)
goto out;
if ((rc = ina231_i2c_write(sensor->client, REG_ALERT_EN, 0x0000)) < 0)
goto out;
if ((rc = ina231_i2c_write(sensor->client, REG_ALERT_LIMIT, 0x0000)) < 0)
goto out;
if ((rc = ina231_i2c_read(sensor->client, REG_CONFIG)) != sensor->pd->config)
goto out;
if ((rc = ina231_i2c_read(sensor->client, REG_CALIBRATION)) != sensor->reg_calibration )
goto out;
if ((rc = ina231_i2c_read(sensor->client, REG_ALERT_EN)) != 0x0000)
goto out;
if ((rc = ina231_i2c_read(sensor->client, REG_ALERT_LIMIT)) != 0x0000)
goto out;
// misc driver probe
if (ina231_misc_probe(sensor) < 0)
goto out;
// sysfs probe
if (ina231_sysfs_create(&client->dev) < 0)
goto out;
// timer run for sensor data receive
INIT_WORK(&sensor->work, ina231_work);
if ((sensor->wq = create_singlethread_workqueue("ina231_wq")) == NULL) goto out;
hrtimer_init(&sensor->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sensor->timer_sec = sensor->pd->update_period / 1000000;
sensor->timer_nsec = sensor->pd->update_period % 1000000;
sensor->timer_nsec = sensor->timer_nsec * 1000;
sensor->timer.function = ina231_timer;
if (sensor->pd->enable) ina231_i2c_enable(sensor);
// display register message
rc = 0;
dev_info(&client->dev, "============= Probe INA231 : %s ============= \n",
sensor->pd->name);
dev_info(&client->dev, "SENSOR ENABLE : %s\n" ,
sensor->pd->enable ? "true" : "false");
dev_info(&client->dev, "REG CONFIG : 0x%04X\n" ,
sensor->pd->config );
dev_info(&client->dev, "REG CALIBRATION : 0x%04X\n" ,
sensor->reg_calibration );
dev_info(&client->dev, "SHUNT Resister : %d mOhm\n",
sensor->pd->shunt_R_mohm );
dev_info(&client->dev, "MAX Current : %d A\n" ,
sensor->pd->max_A );
dev_info(&client->dev, "Current LSB uA : %d uA\n" ,
sensor->cur_lsb_uA );
dev_info(&client->dev, "Conversion Time : %d us\n" ,
sensor->pd->update_period );
dev_info(&client->dev, "=====================================================\n");
return 0;
out:
dev_err(&client->dev, "============= Probe INA231 Fail! : %s (0x%04X) ============= \n",
sensor->pd->name, rc);
return rc;
}
//[*]------------------------------------------------------------------------[*]
static int ina231_i2c_remove(struct i2c_client *client)
{
struct ina231_sensor *sensor = dev_get_drvdata(&client->dev);
// removed sysfs entry
ina231_sysfs_remove(&client->dev);
// removed misc drv
ina231_misc_remove(&client->dev);
// timer
if (sensor->pd->enable) hrtimer_cancel(&sensor->timer);
return 0;
}
//[*]------------------------------------------------------------------------[*]
static const struct i2c_device_id ina231_id[] = {
{ INA231_I2C_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ina231_id);
//[*]------------------------------------------------------------------------[*]
static struct i2c_driver ina231_i2c_driver = {
.driver = {
.name = INA231_I2C_NAME,
.owner = THIS_MODULE,
},
.probe = ina231_i2c_probe,
.remove = ina231_i2c_remove,
.id_table = ina231_id,
};
//[*]------------------------------------------------------------------------[*]
static int __init ina231_i2c_init(void)
{
return i2c_add_driver(&ina231_i2c_driver);
}
module_init(ina231_i2c_init);
//[*]------------------------------------------------------------------------[*]
static void __exit ina231_i2c_exit(void)
{
i2c_del_driver(&ina231_i2c_driver);
}
module_exit(ina231_i2c_exit);
//[*]------------------------------------------------------------------------[*]
//[*]------------------------------------------------------------------------[*]

24
drivers/hardkernel/ina231-i2c.h Executable file
View File

@@ -0,0 +1,24 @@
//[*]--------------------------------------------------------------------------------------------------[*]
//
//
//
// I2C INA231(Sensor) driver
// 2013.07.17
//
//
//[*]--------------------------------------------------------------------------------------------------[*]
#ifndef _INA231_I2C_H_
#define _INA231_I2C_H_
//[*]--------------------------------------------------------------------------------------------------[*]
// extern function define
//[*]--------------------------------------------------------------------------------------------------[*]
extern void ina231_i2c_enable (struct ina231_sensor *sensor);
extern int ina231_i2c_read (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len);
extern int ina231_i2c_write (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len);
//[*]--------------------------------------------------------------------------------------------------[*]
#endif /* _INA231_I2C_H_ */
//[*]--------------------------------------------------------------------------------------------------[*]
//[*]--------------------------------------------------------------------------------------------------[*]

175
drivers/hardkernel/ina231-misc.c Executable file
View File

@@ -0,0 +1,175 @@
//[*]------------------------------------------------------------------------[*]
//
//
// I2C INA231(Sensor) driver
// 2013.07.17
//
//
//[*]------------------------------------------------------------------------[*]
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
//[*]------------------------------------------------------------------------[*]
#include "ina231.h"
#include "ina231-i2c.h"
#include "ina231-misc.h"
//[*]------------------------------------------------------------------------[*]
// Global Sensor struct (sensor struct save for ioctl)
//[*]------------------------------------------------------------------------[*]
struct global_sensor {
struct ina231_sensor *p;
struct list_head list;
};
LIST_HEAD(SensorList);
//[*]------------------------------------------------------------------------[*]
//
// function prototype
//
//[*]------------------------------------------------------------------------[*]
static int ina231_misc_open (struct inode *inode, struct file *file);
static long ina231_misc_ioctl (struct file *file, unsigned int cmd, unsigned long arg);
void ina231_misc_remove (struct device *dev);
int ina231_misc_probe (struct ina231_sensor *sensor);
//[*]------------------------------------------------------------------------[*]
static const struct file_operations ina231_misc_fops = {
.owner = THIS_MODULE,
.open = ina231_misc_open,
.unlocked_ioctl = ina231_misc_ioctl,
};
//[*]------------------------------------------------------------------------[*]
static long ina231_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ina231_sensor *sensor = (struct ina231_sensor *)file->private_data;
struct ina231_iocreg *iocreg = (struct ina231_iocreg *)arg;
switch (cmd) {
// Get regisger
case INA231_IOCGREG:
iocreg->enable = sensor->pd->enable;
if (sensor->pd->enable) {
mutex_lock(&sensor->mutex);
iocreg->cur_uV = sensor->cur_uV;
iocreg->cur_uA = sensor->cur_uA;
iocreg->cur_uW = sensor->cur_uW;
mutex_unlock(&sensor->mutex);
}
else {
iocreg->cur_uV = 0;
iocreg->cur_uA = 0;
iocreg->cur_uW = 0;
}
break;
// Set status
case INA231_IOCSSTATUS:
if (sensor->pd->enable != iocreg->enable) {
sensor->pd->enable = iocreg->enable;
if (sensor->pd->enable) ina231_i2c_enable(sensor);
}
break;
// Set status
case INA231_IOCGSTATUS:
iocreg->enable = sensor->pd->enable;
memset(iocreg->name, 0x00, sizeof(iocreg->name));
memcpy(iocreg->name, sensor->pd->name, sizeof(iocreg->name));
break;
default :
printk("%s : unknown message!!\n", __func__);
break;
}
return 0;
}
//[*]------------------------------------------------------------------------[*]
static int ina231_misc_open(struct inode *inode, struct file *file)
{
struct global_sensor *gsensor;
struct list_head *list_head;
printk("%s : %d\n", __func__, iminor(inode));
list_for_each(list_head, &SensorList)
{
gsensor = list_entry(list_head, struct global_sensor, list);
if (gsensor->p->misc->minor == iminor(inode)) {
printk("find match sensor struct : name = %s\n",
gsensor->p->pd->name);
file->private_data = gsensor->p;
}
}
return 0;
}
//[*]------------------------------------------------------------------------[*]
int ina231_misc_probe(struct ina231_sensor *sensor)
{
int rc;
struct miscdevice *pmisc;
struct global_sensor *gsensor;
if (!(pmisc = devm_kzalloc(&sensor->client->dev,
sizeof(struct miscdevice),
GFP_KERNEL))) {
printk("INA231 Sensor misc struct malloc error!\n");
return -ENOMEM;
}
pmisc->minor = MISC_DYNAMIC_MINOR;
pmisc->name = sensor->pd->name;
pmisc->fops = &ina231_misc_fops;
pmisc->mode = S_IWUGO | S_IRUGO;
sensor->misc = pmisc;
if ((rc = misc_register(sensor->misc)) < 0) {
printk("%s : INA231 misc register fail!\n", __func__);
return rc;
}
if(!(gsensor = (struct global_sensor *)devm_kzalloc(&sensor->client->dev,
sizeof(struct global_sensor),
GFP_KERNEL))) {
printk("%s : INA231 global sensor malloc error!\n", __func__);
return -ENOMEM;
}
else {
gsensor->p = sensor;
list_add(&gsensor->list, &SensorList);
}
return 0;
}
//[*]------------------------------------------------------------------------[*]
void ina231_misc_remove(struct device *dev)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
struct list_head *list_head;
struct global_sensor *gsensor;
misc_deregister(sensor->misc);
list_for_each(list_head, &SensorList)
{
gsensor = list_entry(list_head, struct global_sensor, list);
}
}
//[*]------------------------------------------------------------------------[*]
MODULE_AUTHOR("HardKernel Co., Ltd.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("INA231 Current Sensor Driver");
//[*]------------------------------------------------------------------------[*]
//[*]------------------------------------------------------------------------[*]

View File

@@ -0,0 +1,33 @@
//[*]--------------------------------------------------------------------------------------------------[*]
//
//
//
// I2C INA231(Sensor) driver
// 2013.07.17
//
//
//[*]--------------------------------------------------------------------------------------------------[*]
#ifndef _INA231_MISC_H_
#define _INA231_MISC_H_
//[*]--------------------------------------------------------------------------------------------------[*]
struct ina231_iocreg {
unsigned char name[20];
unsigned int enable;
unsigned int cur_uV;
unsigned int cur_uA;
unsigned int cur_uW;
} __attribute__ ((packed));
#define INA231_IOCGREG _IOR('i', 1, struct ina231_iocreg *)
#define INA231_IOCSSTATUS _IOW('i', 2, struct ina231_iocreg *)
#define INA231_IOCGSTATUS _IOR('i', 3, struct ina231_iocreg *)
//[*]--------------------------------------------------------------------------------------------------[*]
extern void ina231_misc_remove (struct device *dev);
extern int ina231_misc_probe (struct ina231_sensor *sensor);
//[*]--------------------------------------------------------------------------------------------------[*]
#endif // _INA231_MISC_H_
//[*]--------------------------------------------------------------------------------------------------[*]
//[*]--------------------------------------------------------------------------------------------------[*]

236
drivers/hardkernel/ina231-sysfs.c Executable file
View File

@@ -0,0 +1,236 @@
//[*]------------------------------------------------------------------------[*]
//
//
// I2C INA231(Sensor) driver
// 2013.07.17
//
//
//[*]------------------------------------------------------------------------[*]
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/stat.h>
//[*]------------------------------------------------------------------------[*]
#include "ina231.h"
#include "ina231-i2c.h"
#include "ina231-misc.h"
//[*]------------------------------------------------------------------------[*]
//
// sysfs function prototype define
//
//[*]------------------------------------------------------------------------[*]
static ssize_t show_name
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_name, 0660, show_name, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_power
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_W, 0660, show_power, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_current
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_A, 0660, show_current, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_voltage
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_V, 0660, show_voltage, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_max_power
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_maxW, 0660, show_max_power, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_max_current
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_maxA, 0660, show_max_current, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_max_voltage
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(sensor_maxV, 0660, show_max_voltage, NULL);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_enable
(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t set_enable
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static DEVICE_ATTR(enable, 0660, show_enable, set_enable);
//[*]------------------------------------------------------------------------[*]
static ssize_t show_period
(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(update_period, 0660, show_period, NULL);
//[*]------------------------------------------------------------------------[*]
//[*]------------------------------------------------------------------------[*]
static struct attribute *ina231_sysfs_entries[] = {
&dev_attr_sensor_name.attr,
&dev_attr_sensor_W.attr,
&dev_attr_sensor_A.attr,
&dev_attr_sensor_V.attr,
&dev_attr_sensor_maxW.attr,
&dev_attr_sensor_maxA.attr,
&dev_attr_sensor_maxV.attr,
&dev_attr_enable.attr,
&dev_attr_update_period.attr,
NULL
};
static struct attribute_group ina231_attr_group = {
.name = NULL,
.attrs = ina231_sysfs_entries,
};
//[*]------------------------------------------------------------------------[*]
//[*]------------------------------------------------------------------------[*]
static ssize_t show_name
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", sensor->pd->name);
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_power
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
unsigned int value;
mutex_lock(&sensor->mutex);
value = sensor->cur_uW;
mutex_unlock(&sensor->mutex);
return sprintf(buf, "%d.%06d\n", (value/1000000), (value%1000000));
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_max_power
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
unsigned int value;
mutex_lock(&sensor->mutex);
value = sensor->max_uW;
mutex_unlock(&sensor->mutex);
return sprintf(buf, "%d.%06d\n", (value/1000000), (value%1000000));
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_current
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
unsigned int value;
mutex_lock(&sensor->mutex);
value = sensor->cur_uA;
mutex_unlock(&sensor->mutex);
return sprintf(buf, "%d.%06d\n", (value/1000000), (value%1000000));
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_max_current
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
unsigned int value;
mutex_lock(&sensor->mutex);
value = sensor->max_uA;
mutex_unlock(&sensor->mutex);
return sprintf(buf, "%d.%06d\n", (value/1000000), (value%1000000));
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_voltage
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
unsigned int value;
mutex_lock(&sensor->mutex);
value = sensor->cur_uV;
mutex_unlock(&sensor->mutex);
return sprintf(buf, "%d.%06d\n", (value/1000000), (value%1000000));
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_max_voltage
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
unsigned int value;
mutex_lock(&sensor->mutex);
value = sensor->max_uV;
mutex_unlock(&sensor->mutex);
return sprintf(buf, "%d.%06d\n", (value/1000000), (value%1000000));
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_enable
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", sensor->pd->enable);
}
//[*]------------------------------------------------------------------------[*]
static ssize_t set_enable
(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
if (simple_strtol(buf, NULL, 10) != 0) {
if (!sensor->pd->enable) {
sensor->pd->enable = 1;
ina231_i2c_enable(sensor);
}
}
else {
if (sensor->pd->enable) {
sensor->pd->enable = 0;
}
}
return count;
}
//[*]------------------------------------------------------------------------[*]
static ssize_t show_period
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ina231_sensor *sensor = dev_get_drvdata(dev);
return sprintf(buf, "%d usec\n", sensor->pd->update_period);
}
//[*]------------------------------------------------------------------------[*]
int ina231_sysfs_create (struct device *dev)
{
return sysfs_create_group(&dev->kobj, &ina231_attr_group);
}
//[*]------------------------------------------------------------------------[*]
void ina231_sysfs_remove (struct device *dev)
{
sysfs_remove_group(&dev->kobj, &ina231_attr_group);
}
//[*]------------------------------------------------------------------------[*]
//[*]------------------------------------------------------------------------[*]

View File

@@ -0,0 +1,23 @@
//[*]--------------------------------------------------------------------------------------------------[*]
//
//
//
// I2C INA231(Sensor) driver
// 2013.07.17
//
//
//[*]--------------------------------------------------------------------------------------------------[*]
#ifndef _INA231_SYSFS_H_
#define _INA231_SYSFS_H_
//[*]--------------------------------------------------------------------------------------------------[*]
// extern function define
//[*]--------------------------------------------------------------------------------------------------[*]
extern int ina231_sysfs_create (struct device *dev);
extern void ina231_sysfs_remove (struct device *dev);
//[*]--------------------------------------------------------------------------------------------------[*]
#endif /* _INA231_SYSFS_H_ */
//[*]--------------------------------------------------------------------------------------------------[*]
//[*]--------------------------------------------------------------------------------------------------[*]

170
drivers/hardkernel/ina231.h Executable file
View File

@@ -0,0 +1,170 @@
//[*]------------------------------------------------------------------------[*]
//
//
// I2C INA231 Sensor driver (platform data struct)
// 2013.07.17
//
//
//[*]------------------------------------------------------------------------[*]
#ifndef __INA231_H__
#define __INA231_H__
//[*]------------------------------------------------------------------------[*]
#define INA231_I2C_NAME "INA231"
struct i2c_client;
struct misc_dev;
//[*]------------------------------------------------------------------------[*]
// INA231 Register define
//[*]------------------------------------------------------------------------[*]
#define REG_CONFIG 0x00 // R/W
#define REG_SHUNT_VOLT 0x01 // R
#define REG_BUS_VOLT 0x02 // R
#define REG_POWER 0x03 // R
#define REG_CURRENT 0x04 // R
#define REG_CALIBRATION 0x05 // R/W
#define REG_ALERT_EN 0x06 // R/W
#define REG_ALERT_LIMIT 0x07 // R/W
#define FIX_uV_LSB 1250 // fix lsb value 0.00125 V
// ex) CONVERSION_DELAY(eVBUS_CT_140uS, eVSH_CT_150uS, eAVG_1); return uSec
#define CONVERSION_DELAY(x, y, z) ((x + y) * z)
#define INA231_CONFIG(x) ((0x4000 | x) & 0xFFFF)
//[*]------------------------------------------------------------------------[*]
enum {
eAVG_CON_1 = 1,
eAVG_CON_4 = 4,
eAVG_CON_16 = 16,
eAVG_CON_64 = 64,
eAVG_CON_128 = 128,
eAVG_CON_256 = 256,
eAVG_CON_512 = 512,
eAVG_CON_1024 = 1024,
};
enum {
eAVG_1 = 0,
eAVG_4,
eAVG_16,
eAVG_64,
eAVG_128,
eAVG_256,
eAVG_512,
eAVG_1024,
};
#define AVG_BIT(x) (x << 9)
//[*]------------------------------------------------------------------------[*]
enum {
eVBUS_CON_140uS = 140,
eVBUS_CON_204uS = 204,
eVBUS_CON_332uS = 332,
eVBUS_CON_588uS = 588,
eVBUS_CON_1100uS = 1100,
eVBUS_CON_2116uS = 2116,
eVBUS_CON_4156uS = 4156,
eVBUS_CON_8244uS = 8244,
};
enum {
eVBUS_CT_140uS = 0,
eVBUS_CT_204uS,
eVBUS_CT_332uS,
eVBUS_CT_588uS,
eVBUS_CT_1100uS,
eVBUS_CT_2116uS,
eVBUS_CT_4156uS,
eVBUS_CT_8244uS,
};
#define VBUS_CT(x) (x << 6)
//[*]------------------------------------------------------------------------[*]
enum {
eVSH_CON_140uS = 140,
eVSH_CON_204uS = 204,
eVSH_CON_332uS = 332,
eVSH_CON_588uS = 588,
eVSH_CON_1100uS = 1100,
eVSH_CON_2116uS = 2116,
eVSH_CON_4156uS = 4156,
eVSH_CON_8244uS = 8244,
};
enum {
eVSH_CT_140uS = 0,
eVSH_CT_204uS,
eVSH_CT_332uS,
eVSH_CT_588uS,
eVSH_CT_1100uS,
eVSH_CT_2116uS,
eVSH_CT_4156uS,
eVSH_CT_8244uS,
};
#define VSH_CT(x) (x << 3)
//[*]------------------------------------------------------------------------[*]
enum {
ePOWER_DOWN1 = 0,
eSHUNT_VOLT_TRIGGER,
eBUS_VOLT_TRIGGER,
eSHUNT_BUS_VOLT_TRIGGER,
ePOWER_DOWN2,
eSHUNT_VOLT_CONTINUOUS,
eBUS_VOLT_CONTINUOUS,
eSHUNT_BUS_VOLT_CONTINUOUS,
};
#define MODE_SET(x) (x)
//[*]------------------------------------------------------------------------[*]
struct ina231_pd {
unsigned char *name;
unsigned short config;
unsigned int max_A;
unsigned int shunt_R_mohm; // unit = m ohm
unsigned int update_period; // unit = usec
unsigned int enable;
};
//[*]------------------------------------------------------------------------[*]
struct ina231_sensor {
struct i2c_client *client;
struct ina231_pd *pd;
struct miscdevice *misc;
unsigned short reg_calibration;
unsigned short reg_bus_volt;
unsigned short reg_current;
unsigned int cur_lsb_uA;
unsigned int cur_uA;
unsigned int cur_uV;
unsigned int cur_uW;
unsigned int max_uA;
unsigned int max_uV;
unsigned int max_uW;
struct hrtimer timer;
unsigned int timer_sec, timer_nsec;
struct work_struct work;
struct workqueue_struct *wq;
struct mutex mutex;
#if defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend power;
#endif
};
//[*]------------------------------------------------------------------------[*]
#endif // INA231
//[*]------------------------------------------------------------------------[*]
//[*]------------------------------------------------------------------------[*]