diff --git a/drivers/elphel/elphel393-pwr.c b/drivers/elphel/elphel393-pwr.c
index 8d1382056720a27ad02d21163c5c4668eb98b52b..eab48c65173f4e5f6f0d307a68855a5b86975a1b 100644
--- a/drivers/elphel/elphel393-pwr.c
+++ b/drivers/elphel/elphel393-pwr.c
@@ -17,7 +17,7 @@
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see .
*/
-
+#undef DEBUG /* should be before linux/module.h - enables dev_dbg at boot in this file */
#include
#include
#include
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#define DRIVER_DESCRIPTION "Elphel 10393 power supply control"
#define DRIVER_VERSION "1.00"
@@ -42,52 +43,272 @@
#define GPIO_CHIP2_ADDR 0x21
#define LTC3589_ADDR 0x34
+/* TODO: set resistors in device tree to accommodate different revisions ( elphel393_pwr,vp15_r1 = <357000>)*/
+#define VP15_R1 357000
+#define VP15_R2 287000
+#define VCC_SENS01_R1 787000
+#define VCC_SENS01_R2 287000
+#define VCC_SENS23_R1 787000
+#define VCC_SENS23_R2 287000
+#define VP5_R1 523000
+#define VP5_R2 100000
+#define VLDO18_R1 357000
+#define VLDO18_R2 287000
+
+#define PINSTRAPPED_OVEN 1
+#define REF_FIXED_TENTH_MV 8000
+#define REF_VAR_0_TENTH_MV 3625
+#define REF_VAR_STEP_TENTH_MV 125
+#define DEAFULT_TIMEOUT 300 /* number of retries testing pgood before giving up */
+struct pwr_gpio_t {
+ const char * label;
+ int pin;
+ int dir; /* direction: 0 - in, 1 - out*/
+ int out_val; /* output value */
+};
+
struct elphel393_pwr_data_t {
int chip_i2c_addr[3];
+ struct device * ltc3489_dev;
+ struct pwr_gpio_t pwr_gpio [16];
int simulate; /* do not perform actual i2c writes */
struct mutex lock;
+ int pgoot_timeout;
+ int pinstrapped_oven;
};
-struct pwr_gpio_t {
- const char * label;
- int pin;
+struct voltage_reg_t {
+ const char * name;
+ int r1; /* resistor in ohms, if <=0 - r2 is voltage in mv */
+ int r2; /* resistor in ohms, if r1<=0 - voltage in mv */
+ int awe_ref; /* 0 - no control, -1 - margining VP10, -2 - margining VP18 */
+ int awe_en; /* 0 - no control, negative - -1-gpio_index */
+ int awe_pgood; /* 0 - no status , negative - -1-gpio_index */
+ int mask_pgood; /* 1 - temporarily disable pgood when turning on/changing voltage */
+ int awe_slew;
};
+static struct voltage_reg_t voltage_reg[]={
+ {
+ .name="vp15",
+ .r1=VP15_R1,
+ .r2=VP15_R2,
+ .awe_ref=LTC3589_AWE_B1DTV1_REF,
+ .awe_en=0,
+ .awe_pgood=LTC3589_AWE_PGSTAT_SD1,
+ .mask_pgood=1,
+ .awe_slew=LTC3589_AWE_VCCR_SLEW_SD1
+ },
+ {
+ .name="vcc_sens01",
+ .r1=VCC_SENS01_R1,
+ .r2=VCC_SENS01_R2,
+ .awe_ref=LTC3589_AWE_B2DTV2_REF,
+ .awe_en=LTC3589_AWE_OVEN_EN_SD2,
+ .awe_pgood=LTC3589_AWE_PGSTAT_SD2,
+ .mask_pgood=1,
+ .awe_slew=LTC3589_AWE_VCCR_SLEW_SD2
+ },
+ {
+ .name="vcc_sens23",
+ .r1=VCC_SENS23_R1,
+ .r2=VCC_SENS23_R2,
+ .awe_ref=LTC3589_AWE_B3DTV1_REF,
+ .awe_en=LTC3589_AWE_OVEN_EN_SD3,
+ .awe_pgood=LTC3589_AWE_PGSTAT_SD3,
+ .mask_pgood=1,
+ .awe_slew=LTC3589_AWE_VCCR_SLEW_SD3
+ },
+ {
+ .name="vp5",
+ .r1=VP5_R1,
+ .r2=VP5_R2,
+ .awe_ref=0,
+ .awe_en=LTC3589_AWE_OVEN_EN_BB,
+ .awe_pgood=LTC3589_AWE_PGSTAT_BB,
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="vldo18",
+ .r1=VLDO18_R1,
+ .r2=VLDO18_R2,
+ .awe_ref=0,
+ .awe_en= 0,
+ .awe_pgood=LTC3589_AWE_PGSTAT_LDO1,
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="vp33sens01",
+ .r1=-1,
+ .r2=33000,
+ .awe_ref=0,
+ .awe_en= -7, /* SENSPWREN0 */
+ .awe_pgood=0,
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="vp33sens23",
+ .r1=-1,
+ .r2=33000,
+ .awe_ref=0,
+ .awe_en= -8, /* SENSPWREN1 */
+ .awe_pgood=0,
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="mmtavcc10",
+ .r1=-1,
+ .r2=10000,
+ .awe_ref=0,
+ .awe_en= 0,
+ .awe_pgood=-15, /* MGTAVTTGOOD */
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="mmtavtt12",
+ .r1=-1,
+ .r2=12000,
+ .awe_ref=0,
+ .awe_en= 0,
+ .awe_pgood=-15, /* MGTAVTTGOOD */
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="vp10",
+ .r1=-1,
+ .r2=10000,
+ .awe_ref=-1,
+ .awe_en= 0,
+ .awe_pgood=-16, /* PGOOD18 */
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+ {
+ .name="vp18",
+ .r1=-1,
+ .r2=18000,
+ .awe_ref=-2,
+ .awe_en= 0,
+ .awe_pgood=-16, /* PGOOD18 */
+ .mask_pgood=1,
+ .awe_slew=0
+ },
+};
-static struct pwr_gpio_t pwr_gpio [16]={
+static struct pwr_gpio_t pwr_gpio[16]={
/* 0x20: */
- {"PWR_MGB1", 0}, /* 1.8V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
- {"PWR_MG1", 1}, /* 1.8V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
- {"PWR_MGB0", 2}, /* 1.0V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
- {"PWR_MG0", 3}, /* 1.0V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
- {"PWR_FQ0", 4}, /* float - nominal frequency (should float for SS), 0 - 0.67 nominal frequency, 1 - 1.5 nominal frequency */
- {"PWR_SS", 5}, /* Spread spectrum, 0 or float - spread spectrum disabled */
- {"SENSPWREN0", 6}, /* 1 - enable 3.3 power to sensor connectors J6 and J7 (0 or float - disable) */
- {"SENSPWREN1", 7}, /* 1 - enable 3.3 power to sensor connectors J8 and J9 (0 or float - disable) */
+ {"PWR_MGB1", 0, 0, 0}, /* 1.8V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
+ {"PWR_MG1", 1, 0, 0}, /* 1.8V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
+ {"PWR_MGB0", 2, 0, 0}, /* 1.0V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
+ {"PWR_MG0", 3, 0, 0}, /* 1.0V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
+ {"PWR_FQ0", 4, 0, 0}, /* float - nominal frequency (should float for SS), 0 - 0.67 nominal frequency, 1 - 1.5 nominal frequency */
+ {"PWR_SS", 5, 0, 0}, /* Spread spectrum, 0 or float - spread spectrum disabled */
+ {"SENSPWREN0", 6, 0, 0}, /* 1 - enable 3.3 power to sensor connectors J6 and J7 (0 or float - disable) */
+ {"SENSPWREN1", 7, 0, 0}, /* 1 - enable 3.3 power to sensor connectors J8 and J9 (0 or float - disable) */
/* 0x21: */
- {"NSHUTDOWN", 8}, /* (pulled up). 0 - shutdown, 1 normal */
- {"DIS_POR", 9}, /* (pulled down). 0 - normal, 1 - disable POR generation on PGOOD deassertion (needed whil changing voltages) */
- { NULL, 10}, /* Not connected */
- { NULL, 11}, /* Not connected */
- { NULL, 12}, /* Not connected */
- { NULL, 13}, /* Not connected */
- {"MGTAVTTGOOD",14}, /* (input) 1.2V linear regulator status (generated from 1.8V) */
- {"PGOOD18", 15} /* (input). Combines other voltages, can be monitored when DIS_POR is activated */
+ {"NSHUTDOWN", 8, 0, 0}, /* (pulled up). 0 - shutdown, 1 normal */
+ {"DIS_POR", 9, 0, 0}, /* (pulled down). 0 - normal, 1 - disable POR generation on PGOOD deassertion (needed whil changing voltages) */
+ { NULL, 10, 0, 0}, /* Not connected */
+ { NULL, 11, 0, 0}, /* Not connected */
+ { NULL, 12, 0, 0}, /* Not connected */
+ { NULL, 13, 0, 0}, /* Not connected */
+ {"MGTAVTTGOOD",14, 0, 0}, /* (input) 1.2V linear regulator status (generated from 1.8V) */
+ {"PGOOD18", 15, 0, 0} /* (input). Combines other voltages, can be monitored when DIS_POR is activated */
};
-static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf);
+static int make_group (struct device *dev, const char * name,
+ ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+ char *buf),
+ ssize_t (*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 outputs_all_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t configs_all_show(struct device *dev, struct device_attribute *attr, char *buf);
+
+#if 0
+static ssize_t output_state_show(struct device *dev, struct device_attribute *attr, char *buf);
+#endif
+static ssize_t output_en_output_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_en_output_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t outputs_pgood_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t channels_en_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t channels_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t channels_dis_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t channels_dis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_ref_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t pbad_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t enable_por_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t enable_por_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+
+static int por_ctrl(struct device *dev, int disable_por);
+static int get_and_disable_por(struct device *dev, int chn_bits, int * old_dis_por);
+static int reenable_por(struct device *dev);
+static int wait_all_pgood(struct device *dev);
+static int list_chn_bits(char * buf, int chn_bits);
+static int parse_chn_bits(const char * buf);
+static int get_enabled_mask(struct device *dev);
+static int set_enabled_by_mask(struct device *dev, int chn_bits, int enable);
+static int slew_by_mask(struct device *dev, int chn_bits);
+static int get_voltage_channel(const char * name);
+static int get_gpio_index_by_name(const char * name);
+static int gpio_conf_by_index(struct device *dev,int gpio_index, int dir, int val);
+static int get_gpio_pwr_mgx_indices(int chn, int * indices); /* chn = 0 (VP10) or 1 (VP18) */
+static int get_volt_mv(struct device *dev, int chn);
+static int set_volt_mv(struct device *dev, int chn, int v_mv);
+static int get_enable(struct device *dev, int chn);
+static int set_enable(struct device *dev, int chn, int enable);
+static int get_pgood(struct device *dev, int chn);
+/*
+ Voltages:
+ VP10 (on at power up, nominal 1.0V)
+ VP18 (on at power up, nomianl 1.8V)
+ VP15 (SW1, on by pinstrap, nominal 1.5V - may be reduced to 1.35 later)
+ VCC_SENS01 (SW2, nominal 1.8V, max 2.8V)
+ VCC_SENS23 (SW3, nominal 1.8V, max 2.8V)
+ VP5 (nominal 5.0V, not software programmed)
+ VLDO18 (LDO1 - always on)
+ VP33SENS0 - 3.3V to sensors J6,J7
+ VP33SESN1 - 3.3V to sensors J8,J9
+ MGTAVCC10 - 1.0 V, linear from VP18 (pgood controls MGTAVTT12)
+ MGTAVTT12 - 1.2 V, linear from VP18 (pgood available, means both)
+ LTC3589 used channels : LDO1, SW1, SW2, SW3, BB
+
+ TODO: Change VCC_SENS01_R1, VCC_SENS23_R1 to 787K (now 487)
+ */
+
/* root directory */
-//static DEVICE_ATTR(outputs, SYSFS_PERMISSIONS & SYSFS_READONLY, output_description_show, NULL);
-//static DEVICE_ATTR(status, SYSFS_PERMISSIONS & SYSFS_READONLY, status_show, NULL);
static DEVICE_ATTR(simulate, SYSFS_PERMISSIONS, simulate_show, simulate_store);
+static DEVICE_ATTR(output_state, SYSFS_PERMISSIONS & SYSFS_READONLY, outputs_all_show, NULL);
+static DEVICE_ATTR(configs, SYSFS_PERMISSIONS & SYSFS_READONLY, configs_all_show, NULL);
+
+static DEVICE_ATTR(channels_en, SYSFS_PERMISSIONS, channels_en_show, channels_en_store);
+static DEVICE_ATTR(channels_dis,SYSFS_PERMISSIONS, channels_dis_show, channels_dis_store);
+static DEVICE_ATTR(power_good, SYSFS_PERMISSIONS & SYSFS_READONLY, pgood_show, NULL);
+static DEVICE_ATTR(power_bad, SYSFS_PERMISSIONS & SYSFS_READONLY, pbad_show, NULL);
+static DEVICE_ATTR(enable_por, SYSFS_PERMISSIONS, enable_por_show, enable_por_store);
static struct attribute *root_dev_attrs[] = {
&dev_attr_simulate.attr,
+ &dev_attr_output_state.attr,
+ &dev_attr_configs.attr,
+ &dev_attr_channels_en.attr,
+ &dev_attr_channels_dis.attr,
+ &dev_attr_power_good.attr,
+ &dev_attr_power_bad.attr,
+ &dev_attr_enable_por.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
@@ -95,7 +316,46 @@ static const struct attribute_group dev_attr_root_group = {
.name = NULL,
};
-static ssize_t simulate_show (struct device *dev, struct device_attribute *attr, char *buf)
+static int make_group (struct device *dev, const char * name,
+ ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+ char *buf),
+ ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count))
+{
+ 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(voltage_reg)+1)*sizeof(pattrs[0]), GFP_KERNEL);
+ if (!pattrs) return -ENOMEM;
+ dev_attrs = devm_kzalloc(dev, ARRAY_SIZE(voltage_reg)*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(voltage_reg)*sizeof(dev_attrs[0]));
+ memset(attr_group, 0, sizeof(*attr_group));
+ for (index=0;indexname = name;
+ 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 simulate_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
return sprintf(buf, "%d\n",clientdata->simulate);
@@ -103,45 +363,721 @@ static ssize_t simulate_show (struct device *dev, struct device_attribute *attr,
static ssize_t simulate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
sscanf(buf, "%du", &clientdata->simulate);
+ ltc3589_set_simulate(ltc3589_client, clientdata->simulate);
+ return count;
+}
+
+static ssize_t outputs_all_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn, pg;
+ char * cp = buf;
+ for (chn=0;chn0)?get_pgood(dev, chn):-1;
+ buf+=sprintf(buf,"%s: %s %d mV%s\n",
+ voltage_reg[chn].name,
+ get_enable(dev, chn)?"ON":"OFF",
+ get_volt_mv(dev, chn),
+ (pg==1)?", power good":((pg==0)?", power is NOT good":"")
+ );
+ }
+ return buf-cp;
+}
+static ssize_t configs_all_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn, pg;
+ char * cp = buf;
+ for (chn=0;chnattr.name);
+ if (chn<0) return chn;
+ pg=get_pgood(dev, chn);
+ return sprintf(buf,"%s: %s %d mV, %s\n",
+ voltage_reg[chn].name,
+ get_enable(dev, chn)?"ON":"OFF",
+ get_volt_mv(dev, chn),
+ (pg=1)?"power good":((pg==0)?"power is NOT good":"")
+ );
+}
+#endif
+static ssize_t output_en_output_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn;
+ chn=get_voltage_channel(attr->attr.name);
+ if (chn<0) return chn;
+ return sprintf(buf,"%d\n", get_enable(dev, chn));
+}
+
+static ssize_t output_en_output_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int chn, enable;
+ chn=get_voltage_channel(attr->attr.name);
+ if (chn<0) return chn;
+ sscanf(buf, "%du", &enable);
return count;
}
+static ssize_t outputs_pgood_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn;
+ chn=get_voltage_channel(attr->attr.name);
+ if (chn<0) return chn;
+ return sprintf(buf,"%d\n", get_pgood(dev, chn));
+}
+
+static ssize_t channels_en_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn_bits;
+ char * cp=buf;
+ chn_bits=get_enabled_mask(dev);
+ if (chn_bits<0) return chn_bits;
+ buf+=list_chn_bits(buf, chn_bits);
+ buf+=sprintf(buf,"\n");
+ return buf-cp;
+}
+/* also slews DAC(s) if applilcable. Call after changing voltage on enabled channels */
+static ssize_t channels_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int chn_bits,rc,old_dis_por,pre_disabled;
+ chn_bits=parse_chn_bits(buf);
+ pre_disabled=get_and_disable_por(dev, chn_bits, &old_dis_por);
+ if (pre_disabled<0) return pre_disabled;
+ rc=slew_by_mask(dev, chn_bits); /* slew if needed - before enabling, waits for slew over */
+ if (rc<0) return rc;
+ rc=set_enabled_by_mask(dev, chn_bits, 1);
+ if (rc<0) return rc;
+ if (pre_disabled && (old_dis_por==0)){
+ rc=reenable_por(dev); /* will wait pgood */
+ if (rc<0) return rc;
+ }
+ return count;
+}
+
+static ssize_t channels_dis_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn_bits;
+ char * cp=buf;
+ chn_bits=get_enabled_mask(dev);
+ if (chn_bits<0) return chn_bits;
+ chn_bits=~chn_bits;
+ buf+=list_chn_bits(buf, chn_bits);
+ buf+=sprintf(buf,"\n");
+ return buf-cp;
+}
+
+static ssize_t channels_dis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int chn_bits,rc;
+ chn_bits=parse_chn_bits(buf);
+ rc=set_enabled_by_mask(dev, chn_bits, 0);
+ if (rc<0) return rc;
+ return count;
+}
+
+static ssize_t output_ref_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int chn;
+ chn=get_voltage_channel(attr->attr.name);
+ if (chn<0) return chn;
+ return sprintf(buf,"%d\n",get_volt_mv(dev, chn));
+}
+
+static ssize_t output_ref_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int chn, v_mv;
+ int rc,old_dis_por,pre_disabled;
+ chn=get_voltage_channel(attr->attr.name);
+ if (chn<0) return chn;
+ /* if output was enabled, and pgood negation may cause POR, disable POR (later restore) */
+ if (get_enable(dev,chn)) pre_disabled=get_and_disable_por(dev, 1<0) pgood_bits |= (1<pwr_gpio[gpio_disable_por_index].out_val)?0:1);
+}
+
+/* When enable_por is set to 1, it first waits for PGOOD and does not enable POR on error */
+static ssize_t enable_por_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int en_por,rc;
+ sscanf(buf, "%du", &en_por);
+ if (en_por) rc=reenable_por(dev); /* will wait pgood, then enable POR */
+ else rc=por_ctrl(dev, 1); /* disable POR */
+ if (rc<0) return rc;
+ return count;
+}
+
+int por_ctrl(struct device *dev, int disable_por)
+{
+ int gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
+ if (gpio_disable_por_index<0) return gpio_disable_por_index;
+ return gpio_conf_by_index(dev, gpio_disable_por_index, 1, disable_por);
+}
+/*
+ * disable POR (if needed) before changing value or enabling one of the voltages
+ * chn_bits - 1 bit per channel
+ */
+
+static int get_and_disable_por(struct device *dev, int chn_bits, int * old_dis_por)
+{
+ int rc,chn;
+ int gpio_disable_por_index;
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
+ if (gpio_disable_por_index<0) return gpio_disable_por_index;
+ old_dis_por[0]=clientdata->pwr_gpio[gpio_disable_por_index].out_val;
+ for (chn=0;chn=ARRAY_SIZE(voltage_reg)) return 0; /* POR was not required to be disabled */
+ rc = gpio_conf_by_index(dev, gpio_disable_por_index, 1, 1); /* out turn on "disable_por" */
+ if (rc<0) return rc;
+ return 1; /* pgood-based POR was disabled (could already be disabled)*/
+}
+
+/* call if POR was diasabled before changing voltage (value or enabling), after waiting for pgood*/
+static int reenable_por(struct device *dev)
+{
+ int gpio_disable_por_index, rc;
+ gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
+ if (gpio_disable_por_index<0) return gpio_disable_por_index;
+ if (((rc=wait_all_pgood(dev)))<0) return rc;
+ return gpio_conf_by_index(dev, gpio_disable_por_index, 1, 0); /* out turn off "disable_por" */
+}
+
+static int wait_all_pgood(struct device *dev)
+{
+ int ntry,chn,all_good=0;
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+
+ for (ntry=0;ntrypgoot_timeout;ntry++){
+ all_good=1;
+ for (chn=0;chn0) && (get_pgood(dev,chn)!=1)){ /* enabled or always enabled */
+ all_good=0;
+ break;
+ }
+ }
+ if (all_good) break; /* all enabled channels that have pgood control are good */
+ }
+ if (!all_good) return -EAGAIN;
+ return 0;
+}
+
+static int list_chn_bits(char * buf, int chn_bits)
+{
+ int chn;
+ char * cp=buf;
+ for (chn=0;chn0) en_mask|= (1<0){
+ awe |= voltage_reg[chn].awe_en;
+ }
+ }
+ awe &= 0xff; /* just WE mask */
+ if (awe){
+ dev_dbg(dev,"set_enabled_by_mask(), cumulative awe=0x%x\n",awe);
+ ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
+ oven=ltc3589_read_field (ltc3589_client, LTC3589_AWE_OVEN);
+ if (oven<0) return oven;
+ if (enable) oven |= awe;
+ else oven &= ~awe;
+ return ltc3589_write_field (ltc3589_client, oven, LTC3589_AWE_OVEN);
+ }
+ return 0;
+}
+
+static int slew_by_mask(struct device *dev, int chn_bits)
+{
+ /* assuming all slew bits in LTC3589 to be in a single register (LTC3589_AWE_OVEN) */
+ int chn, slew=0,rc,ntry;
+ u32 adwe;
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ struct i2c_client *ltc3589_client;
+ ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
+ dev_dbg(dev,"slew_by_mask(dev,0x%x)\n",chn_bits);
+ for (chn=0;chn%d (slew = 0x%x)\n",adwe,rc,slew);
+ if (rc<0) return rc;
+ /* wait slew over */
+ for (ntry=0;ntrypgoot_timeout;ntry++){
+ rc=ltc3589_read_field(ltc3589_client, LTC3589_AWE_VCCR);
+ dev_dbg(dev,"slew_by_mask():ltc3589_read_field(ltc3589_client, 0x%x)->0x%x(%d)\n",LTC3589_AWE_VCCR,rc,rc);
+ if (rc<0) return rc;
+ if ((rc & slew) ==0 ) break;
+ }
+ if (ntry>=clientdata->pgoot_timeout) return -EAGAIN;
+ }
+ return 0;
+}
+
+/* name should either completely match, or have "_*" suffix */
+static int get_voltage_channel(const char * name)
+{
+ int i;
+ for (i=0;i=ARRAY_SIZE(clientdata->pwr_gpio))) return -EINVAL;
+ if ((clientdata->pwr_gpio[gpio_index].dir==dir) && ((clientdata->pwr_gpio[gpio_index].out_val==val) || (dir==0))){
+ dev_dbg(dev,"GPIO#%d(index=%d) did not change: old dir=%d, new dir=%d, old val = %d, new val=%d\n",
+ clientdata->pwr_gpio[gpio_index].pin,
+ gpio_index,
+ clientdata->pwr_gpio[gpio_index].dir,
+ dir,
+ clientdata->pwr_gpio[gpio_index].out_val,
+ val);
+ return 0;
+ }
+ clientdata->pwr_gpio[gpio_index].dir=dir?1:0;
+ clientdata->pwr_gpio[gpio_index].out_val=val?1:0;
+ if (clientdata->pwr_gpio[gpio_index].dir){
+ if (!clientdata->simulate) rc=gpio_direction_output(clientdata->pwr_gpio[gpio_index].pin, clientdata->pwr_gpio[gpio_index].out_val);
+ dev_dbg(dev,"gpio_direction_output(%d,%d)->%d\n",clientdata->pwr_gpio[gpio_index].pin, clientdata->pwr_gpio[gpio_index].out_val,rc);
+ } else {
+ if (!clientdata->simulate) rc=gpio_direction_input(clientdata->pwr_gpio[gpio_index].pin);
+ dev_dbg(dev,"gpio_direction_input(%d)->%d\n",clientdata->pwr_gpio[gpio_index].pin,rc);
+ }
+ return rc;
+}
+static int get_gpio_pwr_mgx_indices(int chn, int * indices) /* chn = 0 (VP10) or 1 (VP18) */
+{
+ indices[0]=get_gpio_index_by_name(chn?"PWR_MG1": "PWR_MG0");
+ indices[1]=get_gpio_index_by_name(chn?"PWR_MGB1":"PWR_MGB0");
+ return ((indices[0]>=0) && (indices[1]>=0))?0:-EINVAL;
+}
+
+/* calculate output voltage in mV */
+static int get_volt_mv(struct device *dev, int chn)
+{
+ int v_mv,ref,rc;
+ int pwr_mg_indices[2];
+ s64 num;
+ struct i2c_client *ltc3589_client;
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
+ if (voltage_reg[chn].r1<=0) {
+ if (voltage_reg[chn].awe_ref<0) { /* vp10, vp18*/
+ rc= get_gpio_pwr_mgx_indices(-1-voltage_reg[chn].awe_ref,pwr_mg_indices); /* chn = 0 (VP10) or 1 (VP18) */
+ if (rc<0) return rc;
+ if (clientdata->pwr_gpio[pwr_mg_indices[0]].dir==0) ref=0;
+ else if (clientdata->pwr_gpio[pwr_mg_indices[0]].out_val) ref=1;
+ else ref=-1;
+ if (ref) {
+ if (clientdata->pwr_gpio[pwr_mg_indices[1]].dir==0) ref*=15;
+ else if (clientdata->pwr_gpio[pwr_mg_indices[1]].out_val) ref*=10;
+ else ref*= 5;
+ }
+ v_mv=(voltage_reg[chn].r2*(100+ref)*2+10)/2000;
+ } else { /* vp33sens01, vp33sens23, mmtavcc10, mmtavtt12 */
+ v_mv=(voltage_reg[chn].r2+5)/10;
+ }
+
+ } else if (voltage_reg[chn].awe_ref==0){ /* VP5, vldo18 */
+#if 0
+ v_mv=(REF_FIXED_TENTH_MV*(voltage_reg[chn].r1+voltage_reg[chn].r2)+ 5*voltage_reg[chn].r2)/(10*voltage_reg[chn].r2);
+#endif
+ num=((u64) REF_FIXED_TENTH_MV)* (voltage_reg[chn].r1+voltage_reg[chn].r2)+ 5*voltage_reg[chn].r2;
+ v_mv=(int) div64_u64(num, 10*voltage_reg[chn].r2);
+ dev_dbg(dev,"chn=%d REF_FIXED_TENTH_MV=%d .r1=%d .r2=%d v_mv=%d\n",chn, REF_FIXED_TENTH_MV,voltage_reg[chn].r1,voltage_reg[chn].r2,v_mv);
+ } else { /* vp15, vcc_sens01,vcc_sens23 */
+ ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
+ ref=ltc3589_read_field(ltc3589_client, voltage_reg[chn].awe_ref);
+ if (ref<0) return ref;
+ num=(REF_VAR_0_TENTH_MV+ REF_VAR_STEP_TENTH_MV* ref);
+ num=num*(voltage_reg[chn].r1+voltage_reg[chn].r2)+ 5*voltage_reg[chn].r2;
+ v_mv=div64_u64(num, 10*voltage_reg[chn].r2);
+ dev_dbg(dev,"chn=%d ref=%d .r1=%d .r2=%d v_mv=%d\n",chn, ref,voltage_reg[chn].r1,voltage_reg[chn].r2,v_mv);
+ }
+ return v_mv;
+}
+/* 0 - OK, <0 - error */
+/* does not iclude disabling/re-enabling PoR */
+static int set_volt_mv(struct device *dev, int chn, int v_mv)
+{
+ int rc,index,d;
+ s64 num;
+ int pwr_mg_indices[2];
+ struct i2c_client *ltc3589_client;
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
+ dev_dbg(dev,"set_volt_mv(dev,%d,%d),.r1=%d\n",chn,v_mv,voltage_reg[chn].r1);
+ if (voltage_reg[chn].r1<=0) {
+ if (voltage_reg[chn].awe_ref<0) { /* vp10, vp18*/
+ index=(400*v_mv+voltage_reg[chn].r2)/(2*voltage_reg[chn].r2);
+ dev_dbg(dev,"chn=%d v_mv=%d index=%d .r1=%d .r2=%d\n",chn, v_mv, index,voltage_reg[chn].r1,voltage_reg[chn].r2);
+ if ((index<17) || (index>23)) {
+ dev_err(dev,"specified voltage for %s is not in the range %dmV to %d mV\n", voltage_reg[chn].name,
+ (17*voltage_reg[chn].r2)/200,(23*voltage_reg[chn].r2)/200);
+ return -EINVAL;
+ }
+ /* disable -> chnage -> enable (if needed) */
+ rc= get_gpio_pwr_mgx_indices(-1-voltage_reg[chn].awe_ref,pwr_mg_indices); /* chn = 0 (VP10) or 1 (VP18) */
+ if (rc<0) return rc;
+ rc = gpio_conf_by_index(dev,pwr_mg_indices[0], 0, 0); /* disable margining */
+ if (rc < 0)return rc;
+ if (index !=20){
+ /* set margining absolute value */
+ switch (index) {
+ case 17:
+ case 23:
+ rc = gpio_conf_by_index(dev,pwr_mg_indices[1], 0, 0); /* float: +/- 15% */
+ break;
+ case 18:
+ case 22:
+ rc = gpio_conf_by_index(dev,pwr_mg_indices[1], 1, 1); /* out 1: +/- 10% */
+ break;
+ case 19:
+ case 21:
+ rc = gpio_conf_by_index(dev,pwr_mg_indices[1], 1, 0); /* out 0: +/- 5% */
+ break;
+ }
+ if (rc < 0)return rc;
+ /* set margining sign */
+ if (index >20) rc = gpio_conf_by_index(dev,pwr_mg_indices[0], 1, 1); /* out 1: positive margining */
+ else rc = gpio_conf_by_index(dev,pwr_mg_indices[0], 1, 0); /* out 0: negative margining */
+ if (rc < 0)return rc;
+ }
+ } else { /* vp33sens01, vp33sens23, mmtavcc10, mmtavtt12 */
+ return -EINVAL; /* voltage not regulated */
+ }
+ } else if (voltage_reg[chn].awe_ref==0){ /* VP5, vldo18 */
+ return -EINVAL; /* voltage not regulated */
+ } else { /* vp15, vcc_sens01,vcc_sens23 */
+ ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
+#if 0
+ index=((10*v_mv*voltage_reg[chn].r2) -(REF_VAR_0_TENTH_MV-REF_VAR_STEP_TENTH_MV/2)*(voltage_reg[chn].r1+voltage_reg[chn].r2))/
+ ((voltage_reg[chn].r1+voltage_reg[chn].r2)*REF_VAR_STEP_TENTH_MV);
+ num=(10*v_mv*voltage_reg[chn].r2) -(REF_VAR_0_TENTH_MV-REF_VAR_STEP_TENTH_MV/2);
+ num*=(voltage_reg[chn].r1+voltage_reg[chn].r2);
+ index=div64_u64(num, (voltage_reg[chn].r1+voltage_reg[chn].r2)*REF_VAR_STEP_TENTH_MV);
+#endif
+ num= (10LL*v_mv*voltage_reg[chn].r2) - ((s64) (voltage_reg[chn].r1+voltage_reg[chn].r2))*REF_VAR_0_TENTH_MV;
+ d= REF_VAR_STEP_TENTH_MV*(voltage_reg[chn].r1+voltage_reg[chn].r2);
+ index=div64_u64(num +(d>>1), d);
+ dev_dbg(dev,"chn=%d v_mv=%d index=%d .r1=%d .r2=%d\n",chn, v_mv, index,voltage_reg[chn].r1,voltage_reg[chn].r2);
+ dev_dbg(dev,"index=%d\n",index);
+ if ((index<0) || (index>31)){
+ dev_err(dev,"chn=%d v_mv=%d index=%d .r1=%d .r2=%d\n",chn, v_mv, index,voltage_reg[chn].r1,voltage_reg[chn].r2);
+ dev_err(dev,"REF_VAR_0_TENTH_MV=%d REF_VAR_STEP_TENTH_MV=%d\n",REF_VAR_0_TENTH_MV,REF_VAR_STEP_TENTH_MV);
+ dev_err(dev,"specified voltage for %s is not in the range %dmV to %d mV\n", voltage_reg[chn].name,
+ (int) div64_u64((((u64)(REF_VAR_0_TENTH_MV+REF_VAR_STEP_TENTH_MV* 0))*(voltage_reg[chn].r1+voltage_reg[chn].r2)+5*voltage_reg[chn].r2),
+ 10*voltage_reg[chn].r2),
+ (int) div64_u64((((u64)(REF_VAR_0_TENTH_MV+REF_VAR_STEP_TENTH_MV*31))*(voltage_reg[chn].r1+voltage_reg[chn].r2)+5*voltage_reg[chn].r2),
+ 10*voltage_reg[chn].r2));
+ return -EINVAL;
+ }
+ dev_dbg(dev,"ltc3589_client->name= %s\n", ltc3589_client->name);
+ rc=ltc3589_write_field(ltc3589_client, index,voltage_reg[chn].awe_ref);
+ if (rc<0) return rc;
+ }
+ return 0;
+}
+
+/* get output enable state */
+static int get_enable(struct device *dev, int chn)
+{
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
+ if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
+ if (voltage_reg[chn].awe_en==0) {
+ return 2; /* always on */
+ } else if (voltage_reg[chn].awe_en>0){
+ if (clientdata->pinstrapped_oven & voltage_reg[chn].awe_en) return 1; /* pin-strapped on bit */
+ return ltc3589_read_field(ltc3589_client, voltage_reg[chn].awe_en);
+ } else {
+ return (clientdata->pwr_gpio[-1-voltage_reg[chn].awe_en].dir && clientdata->pwr_gpio[-1-voltage_reg[chn].awe_en].out_val)?1:0;
+ }
+}
+
+/* set output enable state */
+static int set_enable(struct device *dev, int chn, int enable)
+{
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
+ if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
+ if (voltage_reg[chn].awe_en==0) {
+ return -EINVAL; /* always on, not controlled */
+ } else if (voltage_reg[chn].awe_en>0){
+ return ltc3589_write_field(ltc3589_client, enable, voltage_reg[chn].awe_en);
+ } else {
+ return gpio_conf_by_index(dev,-1-voltage_reg[chn].awe_en, 1, enable);
+ }
+}
+
+/* get power good state */
+static int get_pgood(struct device *dev, int chn)
+{
+ int rc;
+ struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
+ struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
+ if ((chn<0) || (chn>=ARRAY_SIZE(voltage_reg))) return -EINVAL;
+ if (voltage_reg[chn].awe_pgood==0) {
+ if (((rc=get_enable(dev,chn)))<0) return rc; /* 0 - disabled */
+ return 2; /* no status available */
+ } else if (voltage_reg[chn].awe_pgood>0){
+ return ltc3589_read_field(ltc3589_client, voltage_reg[chn].awe_pgood);
+ } else {
+/* return gpio_get_value(clientdata->pwr_gpio[-1-voltage_reg[chn].awe_pgood].pin); */
+ return gpio_get_value_cansleep(clientdata->pwr_gpio[-1-voltage_reg[chn].awe_pgood].pin);
+ }
+}
+
static int elphel393_pwr_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
+ if (((retval = make_group (dev, "voltages_mv", output_ref_show, output_ref_store)))<0) return retval;
+ if (((retval = make_group (dev, "outputs_en", output_en_output_show, output_en_output_store)))<0) return retval;
+ if (((retval = make_group (dev, "outputs_pgood", outputs_pgood_show, NULL)))<0) return retval;
}
return retval;
}
-static void elphel393_pwr_init_of(struct platform_device *pdev)
+
+static void elphel393_pwr_init_of_i2caddr(struct platform_device *pdev)
{
const __be32 * config_data;
-// struct device *dev = &pdev->dev;
+ int len,i;
struct device_node *node = pdev->dev.of_node;
struct elphel393_pwr_data_t *clientdata = platform_get_drvdata(pdev);
- int len,i;
if (node) {
config_data = of_get_property(node, "elphel393_pwr,i2c_chips", &len);
if (config_data){
len /= sizeof(*config_data);
- dev_info(&pdev->dev,"Found %d items in 'elphel393_pwr,i2c_chips' in the Device Tree\n",len);
+ dev_dbg(&pdev->dev,"Found %d items in 'elphel393_pwr,i2c_chips' in the Device Tree\n",len);
if (len!= ARRAY_SIZE(clientdata->chip_i2c_addr)){
dev_err(&pdev->dev,"Got %d items in 'elphel393_pwr,i2c_chips', expected %d\n",len,ARRAY_SIZE(clientdata->chip_i2c_addr));
return;
}
for (i=0;ichip_i2c_addr[i]=be32_to_cpup(&config_data[i]);
}
+ }
+}
+
+static void elphel393_pwr_init_of(struct platform_device *pdev)
+{
+ const __be32 * config_data;
+ const char * config_string;
+ char str[40];
+ int len,chn,pre_disabled,old_dis_por,rc,chn_bits;
+ struct device_node *node = pdev->dev.of_node;
+ struct elphel393_pwr_data_t *clientdata = platform_get_drvdata(pdev);
+ struct i2c_client *ltc3589_client= to_i2c_client(clientdata->ltc3489_dev);
+
+ if (node) {
+ /* find resistor values */
+ for (chn=0;chn0)){
+ dev_dbg(&pdev->dev,"Found %s=<%d>\n",str,be32_to_cpup(&config_data[0]));
+ voltage_reg[chn].r1=be32_to_cpup(&config_data[0]);
+ }
+ sprintf(str,"elphel393_pwr,%s.r2",voltage_reg[chn].name);
+ config_data = of_get_property(node, str, &len);
+ if (config_data && (len>0)){
+ dev_dbg(&pdev->dev,"Found %s=<%d>\n",str,be32_to_cpup(&config_data[0]));
+ voltage_reg[chn].r2=be32_to_cpup(&config_data[0]);
+ }
+ }
+ /* which channels are enabled by pin-strapping */
+ config_data = of_get_property(node, "elphel393_pwr,pinstrapped_oven", &len);
+ if (config_data && (len>0)){
+ dev_dbg(&pdev->dev,"Found elphel393_pwr,pinstrapped_oven=<%d>\n",be32_to_cpup(&config_data[0]));
+ clientdata->pinstrapped_oven=be32_to_cpup(&config_data[0]);
+ }
+
+ /* debug mode - simulate only, no actual power supply control */
+ config_data = of_get_property(node, "elphel393_pwr,simulate", &len);
+ if (config_data && (len>0)){
+ dev_dbg(&pdev->dev,"Found elphel393_pwr,simulate=<%d>\n",be32_to_cpup(&config_data[0]));
+ clientdata->simulate=config_data[0]?1:0;
+ ltc3589_set_simulate(ltc3589_client, clientdata->simulate);
+ }
+
+ /* disable output voltages (not likely to be needed - maybe for warm reboot) */
+ config_string = of_get_property(node, "elphel393_pwr,channels_disable", &len);
+ if (config_string){
+ dev_dbg(&pdev->dev,"Found elphel393_pwr,channels_disable=\"%s\"\n",config_string);
+ chn_bits=parse_chn_bits(config_string);
+ rc=set_enabled_by_mask(&pdev->dev, chn_bits, 0);
+ if (rc<0) return;
+ }
+ /* set output voltages (target voltages, in mV) */
+ for (chn=0;chn0)){
+ dev_dbg(&pdev->dev,"Found %s=<%d>\n",str,be32_to_cpup(&config_data[0]));
+ if (get_enable(&pdev->dev,chn)) pre_disabled=get_and_disable_por(&pdev->dev, 1<dev,"pre_disabled=%d\n",pre_disabled);
+ rc=set_volt_mv(&pdev->dev, chn,be32_to_cpup(&config_data[0]));
+ dev_dbg(&pdev->dev,"set_volt_mv()->%d\n",rc);
+ if (rc<0) return;
+ if (pre_disabled && (old_dis_por==0)){
+ rc=reenable_por(&pdev->dev); /* will wait pgood */
+ if (rc<0){
+ dev_err(&pdev->dev,"Timeout during wait for power good after chnging voltage for %s before re-enabling POR on power loss\n",\
+ voltage_reg[chn].name);
+ return;
+ }
+ }
+ }
+ }
+ /* enable output voltages */
+ config_string = of_get_property(node, "elphel393_pwr,channels_enable", &len);
+ if (config_string){
+ dev_dbg(&pdev->dev,"Found elphel393_pwr,channels_enable=\"%s\"\n",config_string);
+ chn_bits=parse_chn_bits(config_string);
+ pre_disabled=get_and_disable_por(&pdev->dev, chn_bits, &old_dis_por);
+ if (pre_disabled<0) return;
+ rc=slew_by_mask(&pdev->dev, chn_bits); /* slew if needed - before enabling, waits for slew over */
+ if (rc<0) {
+ dev_err(&pdev->dev,"Timeout during wait for slew over\n");
+ return;
+ }
+ rc=set_enabled_by_mask(&pdev->dev, chn_bits, 1);
+ if (rc<0) return;
+ if (pre_disabled && (old_dis_por==0)){
+ rc=reenable_por(&pdev->dev); /* will wait pgood */
+ if (rc<0) {
+ dev_err(&pdev->dev,"Timeout during wait for power good before re-enabling POR on power loss\n");
+ return;
+ }
+ }
+ }
}
+ dev_info(&pdev->dev,"elphel393_pwr configuration done\n");
}
static int device_by_i2c_addr_match(struct device *dev, void *data)
{
struct i2c_client *client = to_i2c_client(dev);
int *addr = (int *)data;
- dev_info(dev,"addr_given=0x%02x, addr found=0x%02x\n",addr[0],(int) client->addr);
+ dev_dbg(dev,"addr_given=0x%02x, addr found=0x%02x\n",addr[0],(int) client->addr);
return i2c_verify_client(dev) && (client->addr==addr[0]);
}
@@ -154,69 +1090,74 @@ static int i2c_addr_gpiochip_match(struct gpio_chip *chip, void *data)
{
struct i2c_client *client = to_i2c_client(chip->dev);
int *addr = (int *)data;
- dev_info(chip->dev,"addr_given=0x%02x, addr found=0x%02x\n",addr[0],(int) client->addr);
+ dev_dbg(chip->dev,"addr_given=0x%02x, addr found=0x%02x\n",addr[0],(int) client->addr);
return i2c_verify_client(chip->dev) && (client->addr==addr[0]);
}
static int elphel393_pwr_probe(struct platform_device *pdev)
{
struct gpio_chip *chip;
- struct device * ltc3489_dev;
+// struct device * ltc3489_dev;
int i,rc;
int base[2];
struct i2c_client *ltc3589_client;
struct elphel393_pwr_data_t *clientdata = NULL;
- dev_info(&pdev->dev,"+++ Probing elphel393-pwr +++");
+ dev_info(&pdev->dev,"Probing elphel393-pwr\n");
clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL);
+ clientdata->pgoot_timeout=DEAFULT_TIMEOUT;
+ clientdata->pinstrapped_oven=PINSTRAPPED_OVEN;
+
clientdata->chip_i2c_addr[0]=0x20;
clientdata->chip_i2c_addr[1]=0x21;
clientdata->chip_i2c_addr[2]=0x34;
platform_set_drvdata(pdev, clientdata);
elphel393_pwr_sysfs_register(pdev);
- elphel393_pwr_init_of(pdev);
-
+// elphel393_pwr_init_of(pdev);
+ elphel393_pwr_init_of_i2caddr(pdev);
mutex_init(&clientdata->lock);
/* locate GPIO chips by i2c address */
for (i=0;i<2;i++){
chip = gpiochip_find(&clientdata->chip_i2c_addr[i], i2c_addr_gpiochip_match);
base[i]=chip->base;
- dev_info(&pdev->dev,"Found gpio_chip with i2c_addr=0x%02x, label=%s, base=0x%x\n",clientdata->chip_i2c_addr[i],chip->label,base[i]);
+ dev_dbg(&pdev->dev,"Found gpio_chip with i2c_addr=0x%02x, label=%s, base=0x%x\n",clientdata->chip_i2c_addr[i],chip->label,base[i]);
}
for (i=0;i>3]+(i & 7);
- rc=gpio_request(pwr_gpio[i].pin, pwr_gpio[i].label);
+ clientdata->pwr_gpio[i].label=pwr_gpio[i].label;
+ clientdata->pwr_gpio[i].pin=base[i>>3]+(i & 7);
+ clientdata->pwr_gpio[i].dir=0; /* input */
+ clientdata->pwr_gpio[i].out_val=0;
+ rc=gpio_request(clientdata->pwr_gpio[i].pin, clientdata->pwr_gpio[i].label);
if (rc<0){
- dev_err(&pdev->dev," Failed to get GPIO[%d] with label %s\n",pwr_gpio[i].pin,pwr_gpio[i].label);
+ dev_err(&pdev->dev," Failed to get GPIO[%d] with label %s\n",clientdata->pwr_gpio[i].pin,clientdata->pwr_gpio[i].label);
+ return rc;
} else {
- dev_info(&pdev->dev,"Confirmed request GPIO[%d] with label %s\n",pwr_gpio[i].pin,pwr_gpio[i].label);
+ dev_dbg(&pdev->dev,"Confirmed request GPIO[%d] with label %s\n",clientdata->pwr_gpio[i].pin,clientdata->pwr_gpio[i].label);
}
}
/* find ltc3589 */
- ltc3489_dev=find_device_by_i2c_addr(LTC3589_ADDR);
- if (!ltc3489_dev){
+ clientdata->ltc3489_dev=find_device_by_i2c_addr(LTC3589_ADDR);
+ if (!clientdata->ltc3489_dev){
dev_err(&pdev->dev," Failed to find LTC3489 with i2c address 0x%02x\n",LTC3589_ADDR);
return -EIO;
}
- ltc3589_client = to_i2c_client(ltc3489_dev);
-
- dev_info(&pdev->dev,"Located %s with i2c address 0x%02x\n",ltc3589_client->name,LTC3589_ADDR);
- dev_info(&pdev->dev,"LTC3589 status= 0x%02x\n",read_field_ltc3589(ltc3589_client, LTC3589_AWE_PGSTAT));
+ ltc3589_client = to_i2c_client(clientdata->ltc3489_dev);
+
+ dev_dbg(&pdev->dev,"Located %s with i2c address 0x%02x\n",ltc3589_client->name,LTC3589_ADDR);
+ dev_dbg(&pdev->dev,"LTC3589 status= 0x%02x\n",ltc3589_read_field(ltc3589_client, LTC3589_AWE_PGSTAT));
+ elphel393_pwr_init_of(pdev);
return 0;
}
-
static int elphel393_pwr_remove(struct platform_device *pdev)
{
- dev_info(&pdev->dev,"+++ Removing elphel393-pwr +++");
+ dev_info(&pdev->dev,"Removing elphel393-pwr");
return 0;
}
-
-
static struct of_device_id elphel393_pwr_of_match[] = {
{ .compatible = "elphel,elphel393-pwr-1.00", },
{ /* end of table */}