Commit 24abbd9b authored by Andrey Filippov's avatar Andrey Filippov

Adding support for the ltc3589

parent fcf79782
/*!***************************************************************************
*! FILE NAME : ltc3589.c
*! DESCRIPTION: control of the Linear Technology LTC3589 8-channel voltage regulator
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/of.h>
#include <linux/math64.h>
#define DRV_VERSION "1.0"
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
#define CACHE_INIT 1
#define CACHE_VOLAT 2
#define LAST_REG 255
#define AWE_SCR1 0x07ff
#define AWE_SCR1_MODE_SD1 0x0703
#define AWE_SCR1_MODE_SD2 0x070c
#define AWE_SCR1_MODE_SD3 0x0730
#define AWE_SCR1_MODE_BB 0x0740
#define AWE_OVEN 0x10ff
#define AWE_OVEN_EN_SD1 0x1001
#define AWE_OVEN_EN_SD2 0x1002
#define AWE_OVEN_EN_SD3 0x1004
#define AWE_OVEN_EN_BB 0x1008
#define AWE_OVEN_EN_LDO2 0x1010
#define AWE_OVEN_EN_LDO3 0x1020
#define AWE_OVEN_EN_LDO4 0x1040
#define AWE_OVEN_ONLY 0x1080
#define AWE_SCR2 0x12ff
#define AWE_SCR2_NOWAIT_SD1 0x1201
#define AWE_SCR2_NOWAIT_SD2 0x1202
#define AWE_SCR2_NOWAIT_SD3 0x1204
#define AWE_SCR2_NOWAIT_BB 0x1208
#define AWE_SCR2_NOWAIT_LDO2 0x1210
#define AWE_SCR2_NOWAIT_LDO3 0x1220
#define AWE_SCR2_NOWAIT_LDO4 0x1240
#define AWE_SCR2_PGOOD_SHTDN_INH 0x1280
#define AWE_VCCR 0x20ff
#define AWE_VCCR_SLEW_SD1 0x2001 /* self clearing bit */
#define AWE_VCCR_REF_SEL_SD1 0x2002
#define AWE_VCCR_SLEW_SD2 0x2004 /* self clearing bit */
#define AWE_VCCR_REF_SEL_SD2 0x2008
#define AWE_VCCR_SLEW_SD3 0x2010 /* self clearing bit */
#define AWE_VCCR_REF_SEL_SD3 0x2020
#define AWE_VCCR_SLEW_LDO2 0x2040 /* self clearing bit */
#define AWE_VCCR_REF_SEL_LDO2 0x2080
#define AWE_CLIRQ 0x21ff
#define AWE_B1DTV1 0x23ff
#define AWE_B1DTV1_REF 0x231f
#define AWE_B1DTV1_PGMASK 0x2320
#define AWE_B1DTV1_DVDT 0x23c0
#define AWE_B1DTV2 0x24ff
#define AWE_B1DTV2_REF 0x241f
#define AWE_B1DTV2_CLKRATE 0x2420
#define AWE_B1DTV2_PHASE 0x2440
#define AWE_B1DTV2_KEEP_ALIVE 0x2480
#define AWE_VRRCR 0x25ff
#define AWE_VRRCR_SD1 0x2503
#define AWE_VRRCR_SD2 0x250c
#define AWE_VRRCR_SD3 0x2530
#define AWE_VRRCR_LDO2 0x25c0
#define AWE_B2DTV1 0x26ff
#define AWE_B2DTV1_REF 0x261f
#define AWE_B2DTV1_PGMASK 0x2620
#define AWE_B2DTV2 0x27ff
#define AWE_B2DTV2_REF 0x271f
#define AWE_B2DTV2_CLKRATE 0x2720
#define AWE_B2DTV2_PHASE 0x2740
#define AWE_B2DTV2_KEEP_ALIVE 0x2780
#define AWE_B3DTV1 0x29ff
#define AWE_B3DTV1_REF 0x291f
#define AWE_B3DTV1_PGMASK 0x2920
#define AWE_B3DTV2 0x2aff
#define AWE_B3DTV2_REF 0x2a1f
#define AWE_B3DTV2_CLKRATE 0x2a20
#define AWE_B3DTV2_PHASE 0x2a40
#define AWE_B3DTV2_KEEP_ALIVE 0x2a80
#define AWE_L2DTV1 0x32ff
#define AWE_L2DTV1_REF 0x321f
#define AWE_L2DTV1_PGMASK 0x3220
#define AWE_L2DTV1_KEEP_ALIVE 0x3280
#define AWE_L2DTV2 0x33ff
#define AWE_L2DTV2_REF 0x331f
#define AWE_L2DTV2_REF_LDO4 0x3360
#define AWE_L2DTV2_MODE_LDO4 0x3380
#define AWE_IRQSTAT 0x02ff
#define AWE_IRQSTAT_PGOOD_TIMOUT 0x0208
#define AWE_IRQSTAT_NEAR_UV 0x0210
#define AWE_IRQSTAT_HARD_UV 0x0220
#define AWE_IRQSTAT_NEAR_THERM 0x0240
#define AWE_IRQSTAT_HARD_THERM 0x0280
#define AWE_PGSTAT 0x13ff
#define AWE_PGSTAT_LDO1 0x1301
#define AWE_PGSTAT_SD1 0x1302
#define AWE_PGSTAT_SD2 0x1304
#define AWE_PGSTAT_SD3 0x1308
#define AWE_PGSTAT_BB 0x1310
#define AWE_PGSTAT_LDO2 0x1320
#define AWE_PGSTAT_LDO3 0x1340
#define AWE_PGSTAT_LDO4 0x1380
#define LAST_REG 255
struct ltc3589_cache_t {
u8 flags;
u8 data;
};
struct ltc3589_data_t {
int reg_addr; /* used for raw register r/w */
int simulate; /* do not perform actual i2c writes */
struct mutex lock;
struct ltc3589_cache_t cache[LAST_REG+1];
};
static struct i2c_device_id ltc3589_id[] = {
{ "ltc3589", 0 },
{ }
};
struct named_fields_t {
char *name;
u32 awe;
};
static const struct named_fields_t status_fields[]={
{"power_good", AWE_PGSTAT},
{"pgood_ldo1", AWE_PGSTAT_LDO1},
{"pgood_sd1", AWE_PGSTAT_SD1},
{"pgood_sd2", AWE_PGSTAT_SD2},
{"pgood_sd3", AWE_PGSTAT_SD3},
{"pgood_bb", AWE_PGSTAT_BB},
{"pgood_ldo2", AWE_PGSTAT_LDO2},
{"pgood_ldo3", AWE_PGSTAT_LDO3},
{"pgood_ldo4", AWE_PGSTAT_LDO4},
{"irqstat", AWE_IRQSTAT},
{"irqstat_pgoot_timeout",AWE_IRQSTAT_PGOOD_TIMOUT},
{"irqstat_near_uv", AWE_IRQSTAT_NEAR_UV},
{"irqstat_hard_uv", AWE_IRQSTAT_HARD_UV},
{"irqstat_near_therm", AWE_IRQSTAT_NEAR_THERM},
{"irqstat_hard_therm", AWE_IRQSTAT_HARD_THERM},
};
static const struct named_fields_t named_fields[]={
{"ref1_sd1", AWE_B1DTV1_REF},
{"ref2_sd1", AWE_B1DTV2_REF},
{"ref1_sd2", AWE_B2DTV1_REF},
{"ref2_sd2", AWE_B2DTV2_REF},
{"ref1_sd3", AWE_B3DTV1_REF},
{"ref2_sd3", AWE_B3DTV2_REF},
{"ref1_ldo2", AWE_L2DTV1_REF},
{"ref2_ldo2", AWE_L2DTV2_REF},
{"ref_ldo4", AWE_B1DTV1_REF},
{"dv_dt_sd1", AWE_B1DTV1_DVDT},
{"pgood_mask_sd1", AWE_B1DTV1_PGMASK},
{"pgood_mask_sd2", AWE_B2DTV1_PGMASK},
{"pgood_mask_sd3", AWE_B3DTV1_PGMASK},
{"pgood_mask_ldo21",AWE_L2DTV1_PGMASK},
{"clock_rate_sd1", AWE_B1DTV2_CLKRATE},
{"clock_rate_sd2", AWE_B2DTV2_CLKRATE},
{"clock_rate_sd3", AWE_B3DTV2_CLKRATE},
{"clock_phase_sd1", AWE_B1DTV2_PHASE},
{"clock_phase_sd2", AWE_B2DTV2_PHASE},
{"clock_phase_sd3", AWE_B3DTV2_PHASE},
{"keep_alive_sd1", AWE_B1DTV2_KEEP_ALIVE},
{"keep_alive_sd2", AWE_B2DTV2_KEEP_ALIVE},
{"keep_alive_sd3", AWE_B3DTV2_KEEP_ALIVE},
{"keep_alive_ldo2", AWE_L2DTV1_KEEP_ALIVE},
{"slew_rate_sd1", AWE_VRRCR_SD1},
{"slew_rate_sd2", AWE_VRRCR_SD2},
{"slew_rate_sd3", AWE_VRRCR_SD3},
{"slew_rate_ldo2", AWE_VRRCR_LDO2},
{"oven_ldo4", AWE_L2DTV2_MODE_LDO4},
{"oven_only", AWE_OVEN_ONLY},
};
static const int volatile_registers[]={AWE_IRQSTAT_PGOOD_TIMOUT, AWE_PGSTAT_LDO1, AWE_VCCR,-1};
static const char * chn_names[]={"SD1","SD2","SD3","BB","LDO1","LDO2","LDO3","LDO4"};
static const char * modes[]={"continuous","burst","pulse_skip","invalid"};
static const char * pwr_states[]={"power_off","power_on"};
static const char * wait_states[]={"no_wait", "wait"};
static const char * reference_sel[]={"reference_sel1", "reference_sel2"};
/* (register_address << 8) | mask */
static const u32 register_masks[]= {
0x07ff,0x12ff,0x20ff,0x24ff,0x25ff,0x26ff,0x27ff,
0x29ff,0x2aff,0x32ff,0x33ff,0x10ff};
static int make_status_fields(struct device *dev);
static int make_bit_fields(struct device *dev);
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t power_wait_on_off_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t power_wait_on_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pgood_timeout_inhibit_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t pgood_timeout_inhibit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t mode_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t reference_select_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t reference_select_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t reference_select_go_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t reference_select_go_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t field_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t get_field_value (struct device *dev, const char* name, char *buf, int newline);
static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf);
static int get_chn_mode(struct device *dev, char *buf, int chn); /* 0..3 */
static int get_chn_pwr(struct device *dev, char *buf, int chn); /* 0..7 */
static int get_chn_wait(struct device *dev, char *buf, int chn); /* 0..7 */
static int get_ref_sel_go(struct device *dev, char *buf, int chn); /* 0..7 */
static int no_off(const char *str);
static int read_channel_mask(const char * str);
static int read_field (struct i2c_client *client, u32 awe);
static int write_field (struct i2c_client *client, u8 data, u32 awe);
static int write_adwe(struct i2c_client *client, u32 adwe);
static int write_reg(struct i2c_client *client, u8 reg, u8 val, u8 mask);
static int read_reg(struct i2c_client *client, u8 reg);
static void invalidate_cache(struct i2c_client *client);
static int ltc3589_sysfs_register(struct device *dev);
static void ltc3589_init_of(struct i2c_client *client);
static int ltc3589_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id);
static int ltc3589_i2c_remove(struct i2c_client *client);
/* raw access to i2c registers, need to set address (9 bits) first, then r/w data */
static DEVICE_ATTR(invalidate_cache, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, invalidate_cache_store);
static DEVICE_ATTR(simulate, SYSFS_PERMISSIONS, simulate_show, simulate_store);
static DEVICE_ATTR(address, SYSFS_PERMISSIONS, raw_address_show, raw_address_store);
static DEVICE_ATTR(data, SYSFS_PERMISSIONS, raw_data_show, raw_data_store);
static DEVICE_ATTR(hex_address, SYSFS_PERMISSIONS, raw_hex_address_show,raw_hex_address_store);
static DEVICE_ATTR(hex_data, SYSFS_PERMISSIONS, raw_hex_data_show, raw_hex_data_store);
static DEVICE_ATTR(hex_all, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_all_show, NULL);
static DEVICE_ATTR(hex_adwe, SYSFS_PERMISSIONS, raw_hex_adwe_show, raw_hex_adwe_store);
static DEVICE_ATTR(hex_adwe_help, SYSFS_PERMISSIONS & SYSFS_READONLY, raw_hex_adwe_help_show, NULL);
static struct attribute *raw_dev_attrs[] = {
&dev_attr_invalidate_cache.attr,
&dev_attr_simulate.attr,
&dev_attr_address.attr,
&dev_attr_data.attr,
&dev_attr_hex_address.attr,
&dev_attr_hex_data.attr,
&dev_attr_hex_all.attr,
&dev_attr_hex_adwe.attr,
&dev_attr_hex_adwe_help.attr,
NULL
};
static const struct attribute_group dev_attr_raw_group = {
.attrs = raw_dev_attrs,
.name = "raw",
};
//static ssize_t irq_show (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t irq_show_txt (struct device *dev, struct device_attribute *attr, char *buf);
//static ssize_t irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
//static ssize_t pwr_bad_good_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(power_good, SYSFS_PERMISSIONS & SYSFS_READONLY, pwr_bad_good_show, NULL);
static DEVICE_ATTR(power_bad, SYSFS_PERMISSIONS & SYSFS_READONLY, pwr_bad_good_show, NULL);
static DEVICE_ATTR(irq, SYSFS_PERMISSIONS, irq_show, irq_store);
static DEVICE_ATTR(irq_txt, SYSFS_PERMISSIONS, irq_show_txt, irq_store);
static DEVICE_ATTR(power_off, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(power_on, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(wait, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(no_wait, SYSFS_PERMISSIONS, power_wait_on_off_show, power_wait_on_off_store);
static DEVICE_ATTR(reference_sel1, SYSFS_PERMISSIONS, reference_select_show, reference_select_store);
static DEVICE_ATTR(reference_sel2, SYSFS_PERMISSIONS, reference_select_show, reference_select_store);
static DEVICE_ATTR(reference_sel_go, SYSFS_PERMISSIONS, reference_select_go_show, reference_select_go_store);
static DEVICE_ATTR(continuous, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(burst, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(pulse_skip, SYSFS_PERMISSIONS, mode_show, mode_store);
static DEVICE_ATTR(pgood_timeout_inhibit, SYSFS_PERMISSIONS, pgood_timeout_inhibit_show, pgood_timeout_inhibit_store);
static struct attribute *control_dev_attrs[] = {
&dev_attr_power_good.attr,
&dev_attr_power_bad.attr,
&dev_attr_irq.attr,
&dev_attr_irq_txt.attr,
&dev_attr_power_off.attr,
&dev_attr_power_on.attr,
&dev_attr_wait.attr,
&dev_attr_no_wait.attr,
&dev_attr_reference_sel1.attr,
&dev_attr_reference_sel2.attr,
&dev_attr_reference_sel_go.attr,
&dev_attr_continuous.attr,
&dev_attr_burst.attr,
&dev_attr_pulse_skip.attr,
&dev_attr_pgood_timeout_inhibit.attr,
NULL
};
static const struct attribute_group dev_attr_control_group = {
.attrs = control_dev_attrs,
.name = "control",
};
//status_fields[]
static int make_status_fields(struct device *dev)
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(status_fields)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(status_fields)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(status_fields)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;index<ARRAY_SIZE(status_fields);index++) {
dev_attrs[index].attr.name=status_fields[index].name;
dev_attrs[index].attr.mode=SYSFS_PERMISSIONS & SYSFS_READONLY;
dev_attrs[index].show= field_show;
dev_attrs[index].store=NULL;
pattrs[index]=&(dev_attrs[index].attr);
}
pattrs[index]=NULL;
attr_group->name = "status";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static int make_bit_fields(struct device *dev)
{
int retval=-1;
int index;
struct attribute **pattrs; /* array of pointers to attibutes */
struct device_attribute *dev_attrs;
struct attribute_group *attr_group;
pattrs = devm_kzalloc(dev,(ARRAY_SIZE(named_fields)+1)*sizeof(pattrs[0]), GFP_KERNEL);
if (!pattrs) return -ENOMEM;
dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(named_fields)*sizeof(dev_attrs[0]), GFP_KERNEL);
if (!dev_attrs) return -ENOMEM;
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
if (!attr_group) return -ENOMEM;
memset(dev_attrs, 0, ARRAY_SIZE(named_fields)*sizeof(dev_attrs[0]));
memset(attr_group, 0, sizeof(*attr_group));
for (index=0;index<ARRAY_SIZE(named_fields);index++) {
dev_attrs[index].attr.name=named_fields[index].name;
dev_attrs[index].attr.mode=SYSFS_PERMISSIONS;
dev_attrs[index].show= field_show;
dev_attrs[index].store=field_store;
pattrs[index]=&(dev_attrs[index].attr);
}
pattrs[index]=NULL;
attr_group->name = "bit_fields";
attr_group->attrs =pattrs;
dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
if (&dev->kobj) {
retval = sysfs_create_group(&dev->kobj, attr_group);
}
return retval;
}
static ssize_t invalidate_cache_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
invalidate_cache(client);
return count;
}
static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->simulate);
}
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->simulate);
return count;
}
//clientdata->simulate
static ssize_t raw_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%d\n",clientdata->reg_addr);
}
static ssize_t raw_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%du", &clientdata->reg_addr);
return count;
}
static ssize_t raw_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "%d\n",data);
}
static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%du", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_address_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "0x%02x\n",clientdata->reg_addr);
}
static ssize_t raw_hex_address_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct ltc3589_data_t *clientdata=i2c_get_clientdata(to_i2c_client(dev));
sscanf(buf, "%x", &clientdata->reg_addr);
return count;
}
static ssize_t raw_hex_data_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data= read_reg(client, clientdata->reg_addr);
return sprintf(buf, "0x%02x\n",data);
}
static ssize_t raw_hex_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int data;
sscanf(buf, "%x", &data);
write_reg(client, clientdata->reg_addr, data, 0xff); /* write all register, it is up to user to do R-mod-W */
return count;
}
static ssize_t raw_hex_all_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int low_addr=0,reg,data,rc,len=0, count=PAGE_SIZE;
struct i2c_client *client = to_i2c_client(dev);
// struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
for (reg=low_addr;reg<=LAST_REG;reg++) if (count>10){
if ((reg & 0xf) ==0){
rc=sprintf(buf, "%02x: ",reg);
buf+=rc;
len+=rc;
count-=rc;
}
data= read_reg(client, reg); //ignore errors
if (data<0) rc=sprintf(buf, "??");
else rc=sprintf(buf, "%02x",data);
buf+=rc;
len+=rc;
count-=rc;
if (((reg & 0xf) == 0xf) || (reg==LAST_REG)){
rc=sprintf(buf, "\n");
} else {
rc=sprintf(buf, " ");
}
buf+=rc;
len+=rc;
count-=rc;
}
return len;
}
static ssize_t raw_hex_adwe_help_show (struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"Setting one/multiple registers with masks in the form [0x]AADDWW, where AA is register address\n" \
"DD - data byte and WW - write enable bits ( 1 - write, 0 - keep old)\n" \
"When read, provides current register data that can be used in device tree.\n");
}
//static const u32 register_masks[]= {
static ssize_t raw_hex_adwe_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int i,data;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
for (i=0;i<ARRAY_SIZE(register_masks);i++){
if (((data=read_reg(client, register_masks[i]>>8)))<0) return data;
buf+=sprintf(buf," 0x%x",((register_masks[i] & 0x1ff00)<<8) | (register_masks[i] & 0xff) | ((data & 0xff)<<8));
if (((i+1) & 0x7)==0) buf+=sprintf(buf,"\n");
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/*
* accepts single or multiple data, each [0x]AAADDWW - AAA - register address, DD - data byte, WW - write enable mask (1 - write, 0 - keep).
* Ignores any other characters, so same format as in dts with hex data is OK
*/
static ssize_t raw_hex_adwe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
const char hex_digits[]="0123456789abcdefABCDEF";
struct i2c_client *client = to_i2c_client(dev);
struct ltc3589_data_t *clientdata= i2c_get_clientdata(client);
int adwe,rc=0;
int left=count,num_bytes;
char * cp;
mutex_lock(&clientdata->lock);
while ((left>0) && ((cp=strpbrk(buf,hex_digits))) && cp[0]){
left -= (cp-buf);
buf = cp;
dev_dbg(dev,"left=%d", left);
sscanf(buf, "%x%n", &adwe,&num_bytes);
left-=num_bytes;
buf+=num_bytes;
dev_dbg(dev,"left=%d num_bytes=%d, adwe=0x%08x", left,num_bytes,adwe);
if (((rc=write_adwe(client, adwe)))<0) {
mutex_unlock(&clientdata->lock);
return rc;
}
}
mutex_unlock(&clientdata->lock);
return count;
}
//static const char * chn_names[]={"SD1","SD2","SD3","BB","LDO1","LDO2","LDO3","LDO4"};
//static const char * pwr_states[]={"power_off","power_on"};
//static const char * wait_states[]={"no_wait", "wait"};
static ssize_t power_wait_on_off_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,i,invert;
char * cp=buf;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
awe= ((strcmp(attr->attr.name,wait_states[0])==0) || (strcmp(attr->attr.name,wait_states[1])==0))?AWE_SCR2:AWE_OVEN;
invert=((strcmp(attr->attr.name,pwr_states[0])==0) || (strcmp(attr->attr.name,wait_states[0])==0))?0xff:0;
if (((rc=read_field(client,awe)))<0) return rc;
rc=((rc & 0xf) | 0x10 | ((rc & 0x70)<<1)) ^ invert;
for (i=0;i<8;i++) if (rc & (1<<i)) {
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[i]);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t power_wait_on_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
awe= ((strcmp(attr->attr.name,wait_states[0])==0) || (strcmp(attr->attr.name,wait_states[1])==0))?AWE_SCR2:AWE_OVEN;
data=((strcmp(attr->attr.name,pwr_states[0])==0) || (strcmp(attr->attr.name,wait_states[0])==0))?0:0xff;
mask=read_channel_mask(buf);
mask=(mask & 0xf) | ((mask >> 1) & 0x70);
awe = (awe & 0xff00) | mask;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t pgood_timeout_inhibit_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,AWE_SCR2_PGOOD_SHTDN_INH)))<0) return rc;
return sprintf(buf, "%d\n",rc);
}
static ssize_t pgood_timeout_inhibit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,data;
struct i2c_client *client = to_i2c_client(dev);
sscanf(buf, "%d", &data);
if (((rc=write_field(client,data?1:0,AWE_SCR2_PGOOD_SHTDN_INH)))<0) return rc;
return count;
}
static ssize_t mode_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,m,i;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,AWE_SCR1)))<0) return rc;
for (m=0;m<ARRAY_SIZE(modes);m++) if (strcmp(attr->attr.name,modes[m])) break;
if (m>=ARRAY_SIZE(modes)) return -EINVAL;
for (i=0;i<4;i+=2) if (((rc>>i) & 3) == m) {
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[i]);
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,m,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (m=0;m<ARRAY_SIZE(modes);m++) if (strcmp(attr->attr.name,modes[m])) break;
if (m>=ARRAY_SIZE(modes)) return -EINVAL;
mask=read_channel_mask(buf);
mask=((mask & 1)? 3:0) | ((mask & 2)? 0xc:0) | ((mask & 4)? 0x30:0) | ((mask & 8)? 0x40:0);
awe = (AWE_SCR1 & 0xff00) | mask;
data= m | (m<<2) | (m<<4) | (m<<6);
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t reference_select_show (struct device *dev, struct device_attribute *attr, char *buf)
{
int rc,m,i,chn;
char * cp=buf;
struct i2c_client *client = to_i2c_client(dev);
if (((rc=read_field(client,AWE_VCCR)))<0) return rc;
for (m=0;m<ARRAY_SIZE(reference_sel);m++) if (strcmp(attr->attr.name,reference_sel[m])) break;
if (m>=ARRAY_SIZE(reference_sel)) return -EINVAL;
for (i=0;i<4;i++) if (((rc>>(2*i+1)) & 1)==m){
chn=i;
if (i==3) chn=5 ; /* LDO2 */
if (buf!=cp) buf+=sprintf(buf," ");
buf+=sprintf(buf,"%s",chn_names[chn]);
/* if ((rc>>(2*i)) & 1){
buf+=sprintf(buf,"(slewing)");
}
*/
}
buf+=sprintf(buf,"\n");
return buf-cp;
}
/* not raising go */
static ssize_t reference_select_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int rc,mask,m,data;
u32 awe;
struct i2c_client *client = to_i2c_client(dev);
for (m=0;m<ARRAY_SIZE(reference_sel);m++) if (strcmp(attr->attr.name,reference_sel[m])) break;
if (m>=ARRAY_SIZE(reference_sel)) return -EINVAL;
mask=read_channel_mask(buf);
mask=((mask & 1)? 2:0) | ((mask & 2)? 0x8:0) | ((mask & 4)? 0x20:0) | ((mask & 0x20)? 0x80:0);
awe = (AWE_VCCR & 0xff00) | mask;
data= m?0xff:0;
if (((rc=write_field (client, data, awe)))<0) return rc;
return count;
}
static ssize_t reference_select_go_show (struct device *dev, struct device_attribute *attr, char *buf)