From 1306820724d95da59734552e87d53c5111d7a6f7 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Sun, 20 Sep 2020 11:54:41 +0530 Subject: [PATCH] power: supply: smb1390: Add support to make SMB1390 driver GKI compliant Add support for charge pump master and slave power supplies through IIO devices and properties under them through IIO channels under the device. Change-Id: I60e4ae948401ce006c731c5cc09334b7aee7ce07 Signed-off-by: Jishnu Prakash Signed-off-by: Ashish Chavan --- drivers/power/supply/qcom/Kconfig | 2 +- drivers/power/supply/qcom/Makefile | 6 +- .../power/supply/qcom/smb1390-charger-psy.c | 1046 +++++++++++------ 3 files changed, 675 insertions(+), 379 deletions(-) diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 6726c5349698..50da9b959f06 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -71,7 +71,7 @@ config SMB1355_SLAVE_CHARGER config SMB1390_CHARGE_PUMP_PSY tristate "SMB1390 power supply framework based driver" - depends on MFD_I2C_PMIC + depends on MFD_I2C_PMIC && IIO help Say Y to include support for SMB1390 Charge Pump driver based on power supply framework. diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index cf8308643a5e..210241400ffa 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -10,6 +10,6 @@ obj-$(CONFIG_QPNP_SMBLITE) += qpnp-smblite-main.o qpnp-smblite-main-y += step-chg-jeita.o battery.o qpnp-smblite.o smblite-lib.o pmic-voter.o storm-watch.o battery-profile-loader.o schgm-flashlite.o smblite-iio.o obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += qcom-smb1355-charger.o qcom-smb1355-charger-y += smb1355-charger.o pmic-voter.o -obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY) += smb1390-charger-psy.o pmic-voter.o -obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o -obj-$(CONFIG_SMB358_CHARGER) += smb358-charger.o +obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o +obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY) += qcom-smb1390-charger.o +qcom-smb1390-charger-y += smb1390-charger-psy.o pmic-voter.o diff --git a/drivers/power/supply/qcom/smb1390-charger-psy.c b/drivers/power/supply/qcom/smb1390-charger-psy.c index d260b14de572..264e44a063f8 100644 --- a/drivers/power/supply/qcom/smb1390-charger-psy.c +++ b/drivers/power/supply/qcom/smb1390-charger-psy.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "SMB1390: %s: " fmt, __func__ @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -17,7 +16,12 @@ #include #include #include +#include #include +#include +#include + +#define REVID_REVISION4 0x103 #define MISC_CSIR_LSB_REG 0x9F1 #define MISC_CSIR_MSB_REG 0x9F2 @@ -162,7 +166,12 @@ struct smb1390 { struct notifier_block nb; struct wakeup_source *cp_ws; struct dentry *dfs_root; - struct pmic_revid_data *pmic_rev_id; + int rev4; + + unsigned int nchannels; + struct iio_channel **cp_slave_iio_chan_list; + struct iio_chan_spec *cp_iio_chan_ids; + struct iio_channel **smb5_iio_chan_list; /* work structs */ struct work_struct status_change_work; @@ -184,7 +193,6 @@ struct smb1390 { /* power supplies */ struct power_supply *cps_psy; - struct power_supply *usb_psy; struct power_supply *batt_psy; struct power_supply *dc_psy; struct power_supply *cp_master_psy; @@ -268,6 +276,33 @@ struct smb_irq { static const struct smb_irq smb_irqs[]; +struct cp_iio_prop_channels { + const char *datasheet_name; + int channel_no; + enum iio_chan_type type; + long info_mask; +}; + +#define SMB1390_CHAN(_dname, _chno, _type, _mask) \ + { \ + .datasheet_name = _dname, \ + .channel_no = _chno, \ + .type = _type, \ + .info_mask = _mask, \ + }, + +#define SMB1390_CHAN_CUR(_dname, _chno) \ + SMB1390_CHAN(_dname, _chno, IIO_CURRENT, \ + BIT(IIO_CHAN_INFO_PROCESSED)) + +#define SMB1390_CHAN_TEMP(_dname, _chno) \ + SMB1390_CHAN(_dname, _chno, IIO_TEMP, \ + BIT(IIO_CHAN_INFO_PROCESSED)) + +#define SMB1390_CHAN_INDEX(_dname, _chno) \ + SMB1390_CHAN(_dname, _chno, IIO_INDEX, \ + BIT(IIO_CHAN_INFO_PROCESSED)) + static int smb1390_read(struct smb1390 *chip, int reg, int *val) { int rc; @@ -294,6 +329,75 @@ static int smb1390_masked_write(struct smb1390 *chip, int reg, int mask, return rc; } +enum iio_type { + SMB1390_SLAVE, + QPNP_SMB5, +}; + +enum cp_slave_channels { + CURRENT_CAPABILITY = 0, + CP_INPUT_CURRENT_MAX, +}; + +enum smb5_iio_channels { + AICL_DONE = 0, + ADAPTER_CC_MODE, + PD_CURRENT_MAX, + INPUT_CURRENT_SETTLED, + SMB_EN_MODE, + SMB_EN_REASON, +}; + +static const char * const cp_slave_iio_chans[] = { + [CURRENT_CAPABILITY] = "current_capability", + [CP_INPUT_CURRENT_MAX] = "cp_input_current_max", +}; + +static const char * const cp_smb5_ext_iio_chan[] = { + [AICL_DONE] = "aicl_done", + [ADAPTER_CC_MODE] = "adapter_cc_mode", + [PD_CURRENT_MAX] = "pd_current_max", + [INPUT_CURRENT_SETTLED] = "input_current_settled", + [SMB_EN_MODE] = "smb_en_mode", + [SMB_EN_REASON] = "smb_en_reason", +}; + +static int cp_read_iio_prop(struct smb1390 *chip, + enum iio_type type, int iio_chan_id, int *val) +{ + struct iio_channel *iio_chan; + int rc; + + if (type == QPNP_SMB5) { + if (IS_ERR_OR_NULL(chip->smb5_iio_chan_list)) + return -ENODEV; + iio_chan = chip->smb5_iio_chan_list[iio_chan_id]; + } else { + pr_err_ratelimited("iio_type %d is not supported\n", type); + return -EINVAL; + } + + rc = iio_read_channel_processed(iio_chan, val); + return rc < 0 ? rc : 0; +} + +static int cp_write_iio_prop(struct smb1390 *chip, + enum iio_type type, int iio_chan_id, int val) +{ + struct iio_channel *iio_chan; + + if (type == SMB1390_SLAVE) { + if (IS_ERR_OR_NULL(chip->cp_slave_iio_chan_list)) + return -ENODEV; + iio_chan = chip->cp_slave_iio_chan_list[iio_chan_id]; + } else { + pr_err_ratelimited("iio_type %d is not supported\n", type); + return -EINVAL; + } + + return iio_write_channel_raw(iio_chan, val); +} + static bool is_psy_voter_available(struct smb1390 *chip) { if (!chip->batt_psy) { @@ -304,14 +408,6 @@ static bool is_psy_voter_available(struct smb1390 *chip) } } - if (!chip->usb_psy) { - chip->usb_psy = power_supply_get_by_name("usb"); - if (!chip->usb_psy) { - smb1390_dbg(chip, PR_EXT_DEPENDENCY, "Couldn't find usb psy\n"); - return false; - } - } - if (!chip->dc_psy) { chip->dc_psy = power_supply_get_by_name("dc"); if (!chip->dc_psy) { @@ -381,36 +477,68 @@ static int smb1390_isns_mode_control(struct smb1390 *chip, enum isns_mode mode) static bool smb1390_is_adapter_cc_mode(struct smb1390 *chip) { - int rc; - union power_supply_propval pval = {0, }; + int rc, val = 0; - if (!chip->usb_psy) { - chip->usb_psy = power_supply_get_by_name("usb"); - if (!chip->usb_psy) - return false; - } + if (IS_ERR_OR_NULL(chip->smb5_iio_chan_list)) + return false; - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_ADAPTER_CC_MODE, - &pval); + rc = cp_read_iio_prop(chip, QPNP_SMB5, ADAPTER_CC_MODE, &val); if (rc < 0) { pr_err("Couldn't get PPS CC mode status rc=%d\n", rc); return false; } - return pval.intval; + return !!val; +} + +static struct iio_channel **get_ext_channels(struct device *dev, + const char *const *channel_map, int size) +{ + int i, rc = 0; + struct iio_channel **iio_ch_ext; + + iio_ch_ext = devm_kcalloc(dev, size, sizeof(*iio_ch_ext), GFP_KERNEL); + if (!iio_ch_ext) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < size; i++) { + iio_ch_ext[i] = devm_iio_channel_get(dev, channel_map[i]); + + if (IS_ERR(iio_ch_ext[i])) { + rc = PTR_ERR(iio_ch_ext[i]); + if (rc != -EPROBE_DEFER) + dev_err(dev, "%s channel unavailable, %d\n", + channel_map[i], rc); + return ERR_PTR(rc); + } + } + + return iio_ch_ext; } static bool is_cps_available(struct smb1390 *chip) { - if (!chip->cps_psy) - chip->cps_psy = power_supply_get_by_name("cp_slave"); - else - return true; + int rc = 0; + struct iio_channel **iio_list; - if (!chip->cps_psy) + if (IS_ERR(chip->cp_slave_iio_chan_list)) return false; + if (!chip->cp_slave_iio_chan_list) { + iio_list = get_ext_channels(chip->dev, + cp_slave_iio_chans, ARRAY_SIZE(cp_slave_iio_chans)); + if (IS_ERR(iio_list)) { + rc = PTR_ERR(iio_list); + if (rc != -EPROBE_DEFER) { + dev_err(chip->dev, "Failed to get channels, rc=%d\n", + rc); + chip->cp_slave_iio_chan_list = ERR_PTR(-EINVAL); + } + return false; + } + chip->cp_slave_iio_chan_list = iio_list; + } + return true; } @@ -481,7 +609,7 @@ static int smb1390_set_ilim(struct smb1390 *chip, int ilim_ua) return rc; } -static irqreturn_t default_irq_handler(int irq, void *data) +static irqreturn_t smb1390_default_irq_handler(int irq, void *data) { struct smb1390 *chip = data; int i, rc; @@ -513,48 +641,48 @@ static irqreturn_t default_irq_handler(int irq, void *data) static const struct smb_irq smb_irqs[] = { [SWITCHER_OFF_WINDOW_IRQ] = { .name = "switcher-off-window", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [SWITCHER_OFF_FAULT_IRQ] = { .name = "switcher-off-fault", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [TSD_IRQ] = { .name = "tsd-fault", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [IREV_IRQ] = { .name = "irev-fault", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [VPH_OV_HARD_IRQ] = { .name = "vph-ov-hard", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [VPH_OV_SOFT_IRQ] = { .name = "vph-ov-soft", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [ILIM_IRQ] = { .name = "ilim", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, [TEMP_ALARM_IRQ] = { .name = "temp-alarm", - .handler = default_irq_handler, + .handler = smb1390_default_irq_handler, .wake = true, }, }; static int smb1390_get_die_temp(struct smb1390 *chip, - union power_supply_propval *val) + int *val) { int die_temp_deciC = 0; int rc = 0; @@ -581,7 +709,7 @@ static int smb1390_get_die_temp(struct smb1390 *chip, if (rc < 0) pr_err("Couldn't read die chan, rc = %d\n", rc); else - val->intval = die_temp_deciC / 100; + *val = die_temp_deciC / 100; return rc; } @@ -593,9 +721,9 @@ static int smb1390_get_isns(int temp) } static int smb1390_get_isns_master(struct smb1390 *chip, - union power_supply_propval *val) + int *isns_ua) { - int temp = 0; + int temp = 0, val; int rc; bool enable; @@ -623,9 +751,9 @@ static int smb1390_get_isns_master(struct smb1390 *chip, */ mutex_lock(&chip->die_chan_lock); if (is_cps_available(chip)) { - val->intval = ISNS_MODE_STANDBY; - rc = power_supply_set_property(chip->cps_psy, - POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); + val = ISNS_MODE_STANDBY; + rc = cp_write_iio_prop(chip, SMB1390_SLAVE, + CURRENT_CAPABILITY, val); if (rc < 0) { pr_err("Couldn't change slave charging state rc=%d\n", rc); @@ -651,9 +779,9 @@ static int smb1390_get_isns_master(struct smb1390 *chip, pr_err("Couldn't set master to off mode, rc = %d\n", rc); if (is_cps_available(chip)) { - val->intval = ISNS_MODE_OFF; - rc = power_supply_set_property(chip->cps_psy, - POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); + val = ISNS_MODE_OFF; + rc = cp_write_iio_prop(chip, SMB1390_SLAVE, + CURRENT_CAPABILITY, val); if (rc < 0) pr_err("Couldn't change slave charging state rc=%d\n", rc); @@ -663,20 +791,20 @@ unlock: mutex_unlock(&chip->die_chan_lock); if (rc >= 0) - val->intval = smb1390_get_isns(temp); + *isns_ua = smb1390_get_isns(temp); return rc; } static int smb1390_get_isns_slave(struct smb1390 *chip, - union power_supply_propval *val) + int *isns_ua) { - int temp = 0; + int temp = 0, val; int rc; bool enable; if (!is_cps_available(chip)) { - val->intval = 0; + val = 0; return 0; } /* @@ -705,9 +833,9 @@ static int smb1390_get_isns_slave(struct smb1390 *chip, if (rc < 0) goto unlock; - val->intval = ISNS_MODE_ACTIVE; - rc = power_supply_set_property(chip->cps_psy, - POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); + val = ISNS_MODE_ACTIVE; + rc = cp_write_iio_prop(chip, SMB1390_SLAVE, + CURRENT_CAPABILITY, val); if (rc < 0) { pr_err("Couldn't change slave charging state rc=%d\n", rc); @@ -721,9 +849,9 @@ static int smb1390_get_isns_slave(struct smb1390 *chip, goto unlock; } - val->intval = ISNS_MODE_OFF; - rc = power_supply_set_property(chip->cps_psy, - POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); + val = ISNS_MODE_OFF; + rc = cp_write_iio_prop(chip, SMB1390_SLAVE, + CURRENT_CAPABILITY, val); if (rc < 0) pr_err("Couldn't change slave charging state rc=%d\n", rc); @@ -737,13 +865,13 @@ unlock: mutex_unlock(&chip->die_chan_lock); if (rc >= 0) - val->intval = smb1390_get_isns(temp); + *isns_ua = smb1390_get_isns(temp); return rc; } static int smb1390_get_cp_ilim(struct smb1390 *chip, - union power_supply_propval *val) + int *val) { int rc = 0, status; @@ -754,13 +882,11 @@ static int smb1390_get_cp_ilim(struct smb1390 *chip, return -EINVAL; } - val->intval = get_effective_result(chip->ilim_votable); + *val = get_effective_result(chip->ilim_votable); } else { rc = smb1390_read(chip, CORE_FTRIM_ILIM_REG, &status); if (!rc) - val->intval = - ((status & CFG_ILIM_MASK) * 100000) - + 500000; + *val = ((status & CFG_ILIM_MASK) * 100000) + 500000; } return rc; @@ -929,8 +1055,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, int ilim_uA, const char *client) { struct smb1390 *chip = data; - union power_supply_propval pval = {0, }; - int rc = 0; + int rc = 0, val = 0; bool slave_enabled = false; if (!is_psy_voter_available(chip) || chip->suspended) @@ -962,11 +1087,10 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, if (slave_enabled) { ilim_uA /= 2; - pval.intval = DIV_ROUND_CLOSEST(ilim_uA - 500000, + val = DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000); - rc = power_supply_set_property(chip->cps_psy, - POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, - &pval); + rc = cp_write_iio_prop(chip, SMB1390_SLAVE, + CP_INPUT_CURRENT_MAX, val); if (rc < 0) pr_err("Couldn't change slave ilim rc=%d\n", rc); @@ -1048,33 +1172,30 @@ static int smb1390_notifier_cb(struct notifier_block *nb, static void smb1390_configure_ilim(struct smb1390 *chip, int mode) { - int rc; - union power_supply_propval pval = {0, }; + int rc, val = 0; /* PPS adapter reply on the current advertised by the adapter */ - if ((chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VPH) - && (mode == POWER_SUPPLY_CP_PPS)) { - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_PD_CURRENT_MAX, &pval); + if ((chip->pl_output_mode == QTI_POWER_SUPPLY_PL_OUTPUT_VPH) + && (mode == QTI_POWER_SUPPLY_CP_PPS)) { + rc = cp_read_iio_prop(chip, QPNP_SMB5, PD_CURRENT_MAX, &val); if (rc < 0) pr_err("Couldn't get PD CURRENT MAX rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, - true, ILIM_FACTOR(pval.intval)); + true, ILIM_FACTOR(val)); } /* QC3.0/Wireless adapter rely on the settled AICL for USBMID_USBMID */ - if ((chip->pl_input_mode == POWER_SUPPLY_PL_USBMID_USBMID) - && (mode == POWER_SUPPLY_CP_HVDCP3)) { + if ((chip->pl_input_mode == QTI_POWER_SUPPLY_PL_USBMID_USBMID) + && (mode == QTI_POWER_SUPPLY_CP_HVDCP3)) { if (!chip->fcc_main_votable) chip->fcc_main_votable = find_votable("FCC_MAIN"); - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); + rc = cp_read_iio_prop(chip, QPNP_SMB5, INPUT_CURRENT_SETTLED, &val); if (rc < 0) { pr_err("Couldn't get usb aicl rc=%d\n", rc); } else { - vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); + vote(chip->ilim_votable, ICL_VOTER, true, val); /* * Rerun FCC votable to ensure offset for ILIM * compensation is recalculated based on new ILIM. @@ -1090,7 +1211,7 @@ static void smb1390_status_change_work(struct work_struct *work) struct smb1390 *chip = container_of(work, struct smb1390, status_change_work); union power_supply_propval pval = {0, }; - int rc, dc_current_max = 0; + int rc, dc_current_max = 0, val = 0; if (!is_psy_voter_available(chip)) goto out; @@ -1103,16 +1224,14 @@ static void smb1390_status_change_work(struct work_struct *work) if (smb1390_is_batt_soc_valid(chip)) vote(chip->disable_votable, SOC_LEVEL_VOTER, false, 0); - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_SMB_EN_MODE, &pval); + rc = cp_read_iio_prop(chip, QPNP_SMB5, SMB_EN_MODE, &val); if (rc < 0) { pr_err("Couldn't get usb present rc=%d\n", rc); goto out; } - if (pval.intval == POWER_SUPPLY_CHARGER_SEC_CP) { - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_SMB_EN_REASON, &pval); + if (val == QTI_POWER_SUPPLY_CHARGER_SEC_CP) { + rc = cp_read_iio_prop(chip, QPNP_SMB5, SMB_EN_REASON, &val); if (rc < 0) { pr_err("Couldn't get cp reason rc=%d\n", rc); goto out; @@ -1121,7 +1240,7 @@ static void smb1390_status_change_work(struct work_struct *work) /* * Slave SMB1390 is not required for the power-rating of QC3 */ - if (pval.intval != POWER_SUPPLY_CP_HVDCP3) + if (val != QTI_POWER_SUPPLY_CP_HVDCP3) vote(chip->slave_disable_votable, SRC_VOTER, false, 0); /* Check for SOC threshold only once before enabling CP */ @@ -1133,7 +1252,7 @@ static void smb1390_status_change_work(struct work_struct *work) chip->batt_soc_validated = true; } - if (pval.intval == POWER_SUPPLY_CP_WIRELESS) { + if (val == QTI_POWER_SUPPLY_CP_WIRELESS) { vote(chip->ilim_votable, ICL_VOTER, false, 0); rc = power_supply_get_property(chip->dc_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); @@ -1142,19 +1261,17 @@ static void smb1390_status_change_work(struct work_struct *work) } else { dc_current_max = pval.intval; - rc = power_supply_get_property(chip->dc_psy, - POWER_SUPPLY_PROP_AICL_DONE, - &pval); + rc = cp_read_iio_prop(chip, QPNP_SMB5, AICL_DONE, &val); if (rc < 0) pr_err("Couldn't get aicl done rc=%d\n", rc); - else if (pval.intval) + else if (val) vote(chip->ilim_votable, WIRELESS_VOTER, true, dc_current_max); } } else { vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); - smb1390_configure_ilim(chip, pval.intval); + smb1390_configure_ilim(chip, val); } /* @@ -1178,7 +1295,7 @@ static void smb1390_status_change_work(struct work_struct *work) if (rc < 0) { pr_err("Couldn't get charge type rc=%d\n", rc); } else if (pval.intval == - POWER_SUPPLY_CHARGE_TYPE_TAPER) { + POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE) { /* * mutual exclusion is already guaranteed by * chip->status_change_running @@ -1274,7 +1391,7 @@ static void smb1390_taper_work(struct work_struct *work) get_effective_result(chip->fv_votable); } - if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) { + if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE) { delta_fcc_uA = (smb1390_is_adapter_cc_mode(chip) ? CC_MODE_TAPER_DELTA_UA : @@ -1319,236 +1436,34 @@ out: } static enum power_supply_property smb1390_charge_pump_props[] = { - POWER_SUPPLY_PROP_CP_STATUS1, - POWER_SUPPLY_PROP_CP_STATUS2, - POWER_SUPPLY_PROP_CP_ENABLE, - POWER_SUPPLY_PROP_CP_SWITCHER_EN, - POWER_SUPPLY_PROP_CP_DIE_TEMP, - POWER_SUPPLY_PROP_CP_ISNS, - POWER_SUPPLY_PROP_CP_ISNS_SLAVE, - POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER, - POWER_SUPPLY_PROP_CP_IRQ_STATUS, - POWER_SUPPLY_PROP_CP_ILIM, - POWER_SUPPLY_PROP_CHIP_VERSION, - POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, - POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_PARALLEL_MODE, }; -static int smb1390_get_prop_suspended(struct smb1390 *chip, - enum power_supply_property prop, - union power_supply_propval *val) -{ - switch (prop) { - case POWER_SUPPLY_PROP_CP_STATUS1: - val->intval = chip->cp_status1; - break; - case POWER_SUPPLY_PROP_CP_STATUS2: - val->intval = chip->cp_status2; - break; - case POWER_SUPPLY_PROP_CP_ENABLE: - val->intval = chip->cp_enable; - break; - case POWER_SUPPLY_PROP_CP_SWITCHER_EN: - val->intval = chip->switcher_enabled; - break; - case POWER_SUPPLY_PROP_CP_DIE_TEMP: - val->intval = chip->die_temp; - break; - case POWER_SUPPLY_PROP_CP_ISNS: - val->intval = chip->cp_isns_master; - break; - case POWER_SUPPLY_PROP_CP_ISNS_SLAVE: - val->intval = chip->cp_isns_slave; - break; - case POWER_SUPPLY_PROP_CP_IRQ_STATUS: - val->intval = chip->irq_status; - break; - case POWER_SUPPLY_PROP_CP_ILIM: - val->intval = chip->cp_ilim; - break; - default: - return -EINVAL; - } - - return 0; -} - static int smb1390_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) { struct smb1390 *chip = power_supply_get_drvdata(psy); - int rc = 0, status; - bool enable; - - /* - * Return the cached values when the system is in suspend state - * instead of reading the registers to avoid read failures. - */ - if (chip->suspended) { - rc = smb1390_get_prop_suspended(chip, prop, val); - if (!rc) - return rc; - rc = 0; - } switch (prop) { - case POWER_SUPPLY_PROP_CP_STATUS1: - rc = smb1390_read(chip, CORE_STATUS1_REG, &status); - if (!rc) - chip->cp_status1 = val->intval = status; - break; - case POWER_SUPPLY_PROP_CP_STATUS2: - rc = smb1390_read(chip, CORE_STATUS2_REG, &status); - if (!rc) - chip->cp_status2 = val->intval = status; - break; - case POWER_SUPPLY_PROP_CP_ENABLE: - rc = smb1390_get_cp_en_status(chip, SMB_PIN_EN, - &enable); - if (!rc) - chip->cp_enable = val->intval = enable && - !get_effective_result(chip->disable_votable); - break; - case POWER_SUPPLY_PROP_CP_SWITCHER_EN: - rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, - &enable); - if (!rc) - val->intval = enable; - break; - case POWER_SUPPLY_PROP_CP_DIE_TEMP: - /* - * Add a filter to the die temp value read: - * If temp > THERMAL_SUSPEND_DECIDEGC then - * - treat it as an error and report last valid - * cached temperature. - * - return -ENODATA if the cached value is - * invalid. - */ - - rc = smb1390_get_die_temp(chip, val); - if (rc >= 0) { - if (val->intval <= THERMAL_SUSPEND_DECIDEGC) - chip->die_temp = val->intval; - else if (chip->die_temp == -ENODATA) - rc = -ENODATA; - else - val->intval = chip->die_temp; - } - break; - case POWER_SUPPLY_PROP_CP_ISNS: - rc = smb1390_get_isns_master(chip, val); - if (!rc) - chip->cp_isns_master = val->intval; - break; - case POWER_SUPPLY_PROP_CP_ISNS_SLAVE: - rc = smb1390_get_isns_slave(chip, val); - if (!rc) - chip->cp_isns_slave = val->intval; - break; - case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: - val->intval = 0; - break; - case POWER_SUPPLY_PROP_CP_IRQ_STATUS: - /* - * irq_status variable stores provious IRQs that have been - * handled by kernel, but not addressed by user space daemon. - */ - val->intval = chip->irq_status; - rc = smb1390_read(chip, CORE_INT_RT_STS_REG, &status); - if (!rc) - val->intval |= status; - break; - case POWER_SUPPLY_PROP_CP_ILIM: - rc = smb1390_get_cp_ilim(chip, val); - if (!rc) - chip->cp_ilim = val->intval; - break; - case POWER_SUPPLY_PROP_CHIP_VERSION: - val->intval = chip->pmic_rev_id->rev4; - break; - case POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE: - val->intval = chip->pl_output_mode; - break; - case POWER_SUPPLY_PROP_MIN_ICL: - val->intval = chip->min_ilim_ua; - break; case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = (chip->pmic_rev_id->rev4 > 2) ? "SMB1390_V3" : - "SMB1390_V2"; - break; - case POWER_SUPPLY_PROP_PARALLEL_MODE: - val->intval = chip->pl_input_mode; + val->strval = (chip->rev4 > 2) ? "SMB1390_V3" : "SMB1390_V2"; break; default: smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n", prop); - rc = -EINVAL; - } - - return rc; -} - -static int smb1390_set_prop(struct power_supply *psy, - enum power_supply_property prop, - const union power_supply_propval *val) -{ - struct smb1390 *chip = power_supply_get_drvdata(psy); - int rc = 0; - - switch (prop) { - case POWER_SUPPLY_PROP_CP_ENABLE: - vote(chip->disable_votable, USER_VOTER, !val->intval, 0); - break; - case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: - if (val->intval) - cp_toggle_switcher(chip); - break; - case POWER_SUPPLY_PROP_CP_IRQ_STATUS: - chip->irq_status = val->intval; - break; - case POWER_SUPPLY_PROP_CP_ILIM: - if (chip->ilim_votable) - vote_override(chip->ilim_votable, CC_MODE_VOTER, - (val->intval > 0), val->intval); - break; - default: - smb1390_dbg(chip, PR_MISC, "charge pump power supply set prop %d not supported\n", - prop); return -EINVAL; } - return rc; -} - -static int smb1390_prop_is_writeable(struct power_supply *psy, - enum power_supply_property prop) -{ - switch (prop) { - case POWER_SUPPLY_PROP_CP_ENABLE: - case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: - case POWER_SUPPLY_PROP_CP_IRQ_STATUS: - case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: - case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: - case POWER_SUPPLY_PROP_CP_ILIM: - return 1; - default: - break; - } - return 0; } static struct power_supply_desc charge_pump_psy_desc = { .name = "charge_pump_master", - .type = POWER_SUPPLY_TYPE_CHARGE_PUMP, + .type = POWER_SUPPLY_TYPE_MAINS, .properties = smb1390_charge_pump_props, .num_properties = ARRAY_SIZE(smb1390_charge_pump_props), .get_property = smb1390_get_prop, - .set_property = smb1390_set_prop, - .property_is_writeable = smb1390_prop_is_writeable, }; static int smb1390_init_charge_pump_psy(struct smb1390 *chip) @@ -1604,12 +1519,12 @@ static int smb1390_parse_dt(struct smb1390 *chip) &chip->max_cutoff_soc); /* Default parallel output configuration is VPH connection */ - chip->pl_output_mode = POWER_SUPPLY_PL_OUTPUT_VPH; + chip->pl_output_mode = QTI_POWER_SUPPLY_PL_OUTPUT_VPH; of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode", &chip->pl_output_mode); /* Default parallel input configuration is USBMID connection */ - chip->pl_input_mode = POWER_SUPPLY_PL_USBMID_USBMID; + chip->pl_input_mode = QTI_POWER_SUPPLY_PL_USBMID_USBMID; of_property_read_u32(chip->dev->of_node, "qcom,parallel-input-mode", &chip->pl_input_mode); @@ -1666,7 +1581,7 @@ static int smb1390_create_votables(struct smb1390 *chip) * update ilim vote to reflect FCC / 2 value, this is only applicable * when SMB1390 is directly connected to VBAT. */ - if ((chip->pl_output_mode != POWER_SUPPLY_PL_OUTPUT_VPH) + if ((chip->pl_output_mode != QTI_POWER_SUPPLY_PL_OUTPUT_VPH) && chip->fcc_votable) vote(chip->ilim_votable, FCC_VOTER, true, get_effective_result(chip->fcc_votable) / 2); @@ -1852,28 +1767,13 @@ static const struct of_device_id match_table[] = { static int smb1390_master_probe(struct smb1390 *chip) { int rc; - struct device_node *revid_dev_node; - struct pmic_revid_data *pmic_rev_id; - revid_dev_node = of_parse_phandle(chip->dev->of_node, - "qcom,pmic-revid", 0); - if (!revid_dev_node) { - pr_err("Missing qcom,pmic-revid property\n"); - return -EINVAL; + rc = smb1390_read(chip, REVID_REVISION4, &chip->rev4); + if (rc < 0) { + pr_err("Couldn't read REVID_REVISION4, rc=%d\n", rc); + return rc; } - pmic_rev_id = get_revid_data(revid_dev_node); - of_node_put(revid_dev_node); - if (IS_ERR_OR_NULL(pmic_rev_id)) { - /* - * the revid peripheral must be registered, any failure - * here only indicates that the rev-id module has not - * probed yet. - */ - return -EPROBE_DEFER; - } - - chip->pmic_rev_id = pmic_rev_id; spin_lock_init(&chip->status_change_lock); mutex_init(&chip->die_chan_lock); @@ -1902,10 +1802,9 @@ static int smb1390_master_probe(struct smb1390 *chip) goto out_work; } - smb1390_dbg(chip, PR_INFO, "Detected revid=0x%02x\n", - chip->pmic_rev_id->rev4); - if (chip->pmic_rev_id->rev4 <= 0x02 && chip->pl_output_mode != - POWER_SUPPLY_PL_OUTPUT_VPH) { + smb1390_dbg(chip, PR_INFO, "Detected revid=0x%02x\n", chip->rev4); + if (chip->rev4 <= 0x02 && chip->pl_output_mode != + QTI_POWER_SUPPLY_PL_OUTPUT_VPH) { pr_err("Incompatible SMB1390 HW detected, Disabling the charge pump\n"); if (chip->disable_votable) vote(chip->disable_votable, HW_DISABLE_VOTER, @@ -1946,16 +1845,9 @@ out_work: } static enum power_supply_property smb1390_cp_slave_props[] = { - POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, - POWER_SUPPLY_PROP_CURRENT_CAPABILITY, + POWER_SUPPLY_PROP_MODEL_NAME, }; -static int smb1390_slave_prop_is_writeable(struct power_supply *psy, - enum power_supply_property prop) -{ - return 0; -} - static int smb1390_cp_slave_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -1963,16 +1855,8 @@ static int smb1390_cp_slave_get_prop(struct power_supply *psy, struct smb1390 *chip = power_supply_get_drvdata(psy); switch (psp) { - case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: - val->intval = 0; - if (!chip->ilim_votable) - chip->ilim_votable = find_votable("CP_ILIM"); - if (chip->ilim_votable) - val->intval = - get_effective_result_locked(chip->ilim_votable); - break; - case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: - val->intval = (int)chip->current_capability; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = (chip->rev4 > 2) ? "SMB1390_V3" : "SMB1390_V2"; break; default: smb1390_dbg(chip, PR_MISC, "SMB 1390 slave power supply get prop %d not supported\n", @@ -1983,38 +1867,12 @@ static int smb1390_cp_slave_get_prop(struct power_supply *psy, return 0; } -static int smb1390_cp_slave_set_prop(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *val) -{ - struct smb1390 *chip = power_supply_get_drvdata(psy); - int rc = 0; - - switch (psp) { - case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: - rc = smb1390_set_ilim(chip, val->intval); - break; - case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: - chip->current_capability = (enum isns_mode)val->intval; - rc = smb1390_isns_mode_control(chip, val->intval); - break; - default: - smb1390_dbg(chip, PR_MISC, "SMB 1390 slave power supply set prop %d not supported\n", - psp); - return -EINVAL; - } - - return 0; -}; - static const struct power_supply_desc cps_psy_desc = { .name = "cp_slave", - .type = POWER_SUPPLY_TYPE_PARALLEL, + .type = POWER_SUPPLY_TYPE_MAINS, .properties = smb1390_cp_slave_props, .num_properties = ARRAY_SIZE(smb1390_cp_slave_props), .get_property = smb1390_cp_slave_get_prop, - .set_property = smb1390_cp_slave_set_prop, - .property_is_writeable = smb1390_slave_prop_is_writeable, }; static int smb1390_init_cps_psy(struct smb1390 *chip) @@ -2034,6 +1892,340 @@ static int smb1390_init_cps_psy(struct smb1390 *chip) return 0; } +/* master IIO configuration */ +static const struct cp_iio_prop_channels cp_master_chans[] = { + SMB1390_CHAN_INDEX("cp_master_cp_status_1", PSY_IIO_CP_STATUS1) + SMB1390_CHAN_INDEX("cp_master_cp_status_2", PSY_IIO_CP_STATUS2) + SMB1390_CHAN_INDEX("cp_master_cp_enable", PSY_IIO_CP_ENABLE) + SMB1390_CHAN_INDEX("cp_master_cp_switcher_en", PSY_IIO_CP_SWITCHER_EN) + SMB1390_CHAN_TEMP("cp_master_cp_die_temp", PSY_IIO_CP_DIE_TEMP) + SMB1390_CHAN_CUR("cp_master_cp_isns", PSY_IIO_CP_ISNS) + SMB1390_CHAN_CUR("cp_master_cp_isns_slave", PSY_IIO_CP_ISNS_SLAVE) + SMB1390_CHAN_INDEX("cp_master_cp_toggle_switcher", + PSY_IIO_CP_TOGGLE_SWITCHER) + SMB1390_CHAN_INDEX("cp_master_cp_irq_status", PSY_IIO_IRQ_STATUS) + SMB1390_CHAN_CUR("cp_master_cp_ilim", PSY_IIO_CP_ILIM) + SMB1390_CHAN_INDEX("cp_master_chip_version", PSY_IIO_CHIP_VERSION) + SMB1390_CHAN_INDEX("cp_master_parallel_mode", PSY_IIO_PARALLEL_MODE) + SMB1390_CHAN_INDEX("cp_master_parallel_output_mode", + PSY_IIO_PARALLEL_OUTPUT_MODE) + SMB1390_CHAN_CUR("cp_master_min_icl", PSY_IIO_MIN_ICL) +}; + +static int cp_master_iio_set_prop(struct smb1390 *chip, + int channel, int val) +{ + switch (channel) { + case PSY_IIO_CP_ENABLE: + vote(chip->disable_votable, USER_VOTER, !val, 0); + break; + case PSY_IIO_CP_TOGGLE_SWITCHER: + if (!!val) + cp_toggle_switcher(chip); + break; + case PSY_IIO_IRQ_STATUS: + chip->irq_status = val; + break; + case PSY_IIO_CP_ILIM: + if (chip->ilim_votable) + vote_override(chip->ilim_votable, CC_MODE_VOTER, + (val > 0), val); + break; + default: + pr_err("SMB 1390 master get prop %d is not supported\n", channel); + return -EINVAL; + } + + return 0; +} + +static int smb1390_get_prop_suspended(struct smb1390 *chip, + int channel, int *val) +{ + switch (channel) { + case PSY_IIO_CP_STATUS1: + *val = chip->cp_status1; + break; + case PSY_IIO_CP_STATUS2: + *val = chip->cp_status2; + break; + case PSY_IIO_CP_ENABLE: + *val = chip->cp_enable; + break; + case PSY_IIO_CP_SWITCHER_EN: + *val = chip->switcher_enabled; + break; + case PSY_IIO_CP_DIE_TEMP: + *val = chip->die_temp; + break; + case PSY_IIO_CP_ISNS: + *val = chip->cp_isns_master; + break; + case PSY_IIO_CP_ISNS_SLAVE: + *val = chip->cp_isns_slave; + break; + case PSY_IIO_IRQ_STATUS: + *val = chip->irq_status; + break; + case PSY_IIO_CP_ILIM: + *val = chip->cp_ilim; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cp_master_iio_get_prop(struct smb1390 *chip, + int channel, int *val) +{ + int rc = 0, status; + bool enable; + + /* + * Return the cached values when the system is in suspend state + * instead of reading the registers to avoid read failures. + */ + if (chip->suspended) { + rc = smb1390_get_prop_suspended(chip, channel, val); + if (!rc) + return rc; + rc = 0; + } + + switch (channel) { + case PSY_IIO_CP_STATUS1: + rc = smb1390_read(chip, CORE_STATUS1_REG, &status); + if (!rc) + chip->cp_status1 = *val = status; + break; + case PSY_IIO_CP_STATUS2: + rc = smb1390_read(chip, CORE_STATUS2_REG, &status); + if (!rc) + chip->cp_status2 = *val = status; + break; + case PSY_IIO_CP_ENABLE: + rc = smb1390_get_cp_en_status(chip, SMB_PIN_EN, + &enable); + if (!rc) + chip->cp_enable = *val = enable && + !get_effective_result(chip->disable_votable); + break; + case PSY_IIO_CP_SWITCHER_EN: + rc = smb1390_get_cp_en_status(chip, SWITCHER_EN, + &enable); + if (!rc) + *val = enable; + break; + case PSY_IIO_CP_DIE_TEMP: + /* + * Add a filter to the die temp value read: + * If temp > THERMAL_SUSPEND_DECIDEGC then + * - treat it as an error and report last valid + * cached temperature. + * - return -ENODATA if the cached value is + * invalid. + */ + + rc = smb1390_get_die_temp(chip, val); + if (rc >= 0) { + if (*val <= THERMAL_SUSPEND_DECIDEGC) + chip->die_temp = *val; + else if (chip->die_temp == -ENODATA) + rc = -ENODATA; + else + *val = chip->die_temp; + } + break; + case PSY_IIO_CP_ISNS: + rc = smb1390_get_isns_master(chip, val); + if (!rc) + chip->cp_isns_master = *val; + break; + case PSY_IIO_CP_ISNS_SLAVE: + rc = smb1390_get_isns_slave(chip, val); + if (!rc) + chip->cp_isns_slave = *val; + break; + case PSY_IIO_CP_TOGGLE_SWITCHER: + *val = 0; + break; + case PSY_IIO_IRQ_STATUS: + /* + * irq_status variable stores provious IRQs that have been + * handled by kernel, but not addressed by user space daemon. + */ + *val = chip->irq_status; + rc = smb1390_read(chip, CORE_INT_RT_STS_REG, &status); + if (!rc) + *val |= status; + break; + case PSY_IIO_CP_ILIM: + rc = smb1390_get_cp_ilim(chip, val); + if (!rc) + chip->cp_ilim = *val; + break; + case PSY_IIO_CHIP_VERSION: + *val = chip->rev4; + break; + case PSY_IIO_PARALLEL_OUTPUT_MODE: + *val = chip->pl_output_mode; + break; + case PSY_IIO_MIN_ICL: + *val = chip->min_ilim_ua; + break; + case PSY_IIO_PARALLEL_MODE: + *val = chip->pl_input_mode; + break; + default: + smb1390_dbg(chip, PR_MISC, "charge pump get prop %d not supported\n", + channel); + rc = -EINVAL; + } + + if (rc < 0 && rc != -ENODATA) { + pr_err("Couldn't get prop %d rc = %d\n", channel, rc); + return rc; + } + + return IIO_VAL_INT; +} + +static int cp_master_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct smb1390 *iio_chip = iio_priv(indio_dev); + int channel; + + channel = chan->channel; + + return cp_master_iio_set_prop(iio_chip, channel, val); +} + +static int cp_master_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct smb1390 *iio_chip = iio_priv(indio_dev); + int channel; + + channel = chan->channel; + + return cp_master_iio_get_prop(iio_chip, channel, val); +} + +/* slave IIO configuration */ +static const struct cp_iio_prop_channels cp_slave_chans[] = { + SMB1390_CHAN_CUR("cp_slave_input_current_max", + PSY_IIO_CP_INPUT_CURRENT_MAX) + SMB1390_CHAN_CUR("cp_slave_current_capability", + PSY_IIO_CURRENT_CAPABILITY) +}; + +static int cp_slave_iio_set_prop(struct smb1390 *chip, + int channel, int val) +{ + int rc = 0; + + switch (channel) { + case PSY_IIO_CP_INPUT_CURRENT_MAX: + rc = smb1390_set_ilim(chip, val); + break; + case PSY_IIO_CURRENT_CAPABILITY: + chip->current_capability = (enum isns_mode)val; + rc = smb1390_isns_mode_control(chip, val); + break; + default: + smb1390_dbg(chip, PR_MISC, "SMB 1390 slave get prop %d is not supported\n", + channel); + rc = -EINVAL; + break; + } + + if (rc < 0) { + pr_err("Couldn't set prop %d rc = %d\n", channel, rc); + return rc; + } + + return 0; +}; + +static int cp_slave_iio_get_prop(struct smb1390 *chip, + int channel, int *val) +{ + switch (channel) { + case PSY_IIO_CP_INPUT_CURRENT_MAX: + *val = 0; + if (!chip->ilim_votable) + chip->ilim_votable = find_votable("CP_ILIM"); + if (chip->ilim_votable) + *val = get_effective_result_locked(chip->ilim_votable); + break; + case PSY_IIO_CURRENT_CAPABILITY: + *val = (int)chip->current_capability; + break; + default: + pr_err("SMB 1390 slave get prop %d is not supported\n", channel); + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static int cp_slave_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct smb1390 *iio_chip = iio_priv(indio_dev); + int channel; + + channel = chan->channel; + + return cp_slave_iio_set_prop(iio_chip, channel, val); +} + +static int cp_slave_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct smb1390 *iio_chip = iio_priv(indio_dev); + int channel; + + channel = chan->channel; + + return cp_slave_iio_get_prop(iio_chip, channel, val); +} + +static int cp_of_xlate(struct iio_dev *indio_dev, + const struct of_phandle_args *iiospec) +{ + struct smb1390 *iio_chip = iio_priv(indio_dev); + int i; + struct iio_chan_spec *iio_chan = iio_chip->cp_iio_chan_ids; + + for (i = 0; i < iio_chip->nchannels; i++) { + if (iio_chan->channel == iiospec->args[0]) + return i; + iio_chan++; + } + + return -EINVAL; +} + +static const struct iio_info cp_master_iio_info = { + .read_raw = cp_master_read_raw, + .write_raw = cp_master_write_raw, + .of_xlate = cp_of_xlate, +}; + +static const struct iio_info cp_slave_iio_info = { + .read_raw = cp_slave_read_raw, + .write_raw = cp_slave_write_raw, + .of_xlate = cp_of_xlate, +}; + static int smb1390_slave_probe(struct smb1390 *chip) { int stat, rc; @@ -2045,6 +2237,12 @@ static int smb1390_slave_probe(struct smb1390 *chip) return -EINVAL; } + rc = smb1390_read(chip, REVID_REVISION4, &chip->rev4); + if (rc < 0) { + pr_err("Couldn't read REVID_REVISION4, rc=%d\n", rc); + return rc; + } + rc = smb1390_triple_init_hw(chip); if (rc < 0) return rc; @@ -2065,15 +2263,79 @@ static int smb1390_slave_probe(struct smb1390 *chip) return rc; } +static int cp_smb5_iio_init(struct smb1390 *chip) +{ + int rc = 0; + struct iio_channel **iio_list; + + if (IS_ERR(chip->smb5_iio_chan_list)) + return -EINVAL; + + iio_list = get_ext_channels(chip->dev, + cp_smb5_ext_iio_chan, ARRAY_SIZE(cp_smb5_ext_iio_chan)); + if (IS_ERR(iio_list)) { + rc = PTR_ERR(iio_list); + if (rc != -EPROBE_DEFER) { + dev_err(chip->dev, "Failed to get channels, rc=%d\n", + rc); + chip->smb5_iio_chan_list = ERR_PTR(-EINVAL); + } + return rc; + } + + chip->smb5_iio_chan_list = iio_list; + return 0; +} + +static int cp_iio_probe_init(struct smb1390 *chip, + struct iio_dev *indio_dev, const struct cp_iio_prop_channels *cp_chans, + const struct iio_info *cp_iio_info) +{ + int i; + struct iio_chan_spec *iio_chan; + + chip->cp_iio_chan_ids = devm_kcalloc(chip->dev, chip->nchannels, + sizeof(*chip->cp_iio_chan_ids), GFP_KERNEL); + if (!chip->cp_iio_chan_ids) + return -ENOMEM; + + for (i = 0; i < chip->nchannels; i++) { + iio_chan = &chip->cp_iio_chan_ids[i]; + + iio_chan->channel = cp_chans[i].channel_no; + iio_chan->datasheet_name = + cp_chans[i].datasheet_name; + iio_chan->extend_name = cp_chans[i].datasheet_name; + iio_chan->info_mask_separate = + cp_chans[i].info_mask; + iio_chan->type = cp_chans[i].type; + iio_chan->address = i; + } + + if (chip->cp_role == CP_MASTER) { + cp_smb5_iio_init(chip); + indio_dev->name = "smb1390-cp-master"; + } else { + indio_dev->name = "smb1390-cp-slave"; + } + + indio_dev->info = cp_iio_info; + + return 0; +} + static int smb1390_probe(struct platform_device *pdev) { struct smb1390 *chip; + struct iio_dev *indio_dev; int rc; - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*chip)); + if (!indio_dev) return -ENOMEM; + chip = iio_priv(indio_dev); + chip->dev = &pdev->dev; chip->die_temp = -ENODATA; chip->disabled = true; @@ -2088,10 +2350,26 @@ static int smb1390_probe(struct platform_device *pdev) chip->cp_role = (int)of_device_get_match_data(chip->dev); switch (chip->cp_role) { case CP_MASTER: + chip->nchannels = ARRAY_SIZE(cp_master_chans); rc = smb1390_master_probe(chip); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + dev_err(chip->dev, "Couldn't probe SMB1390 master rc= %d\n", + rc); + goto cleanup; + } + rc = cp_iio_probe_init(chip, indio_dev, cp_master_chans, &cp_master_iio_info); break; case CP_SLAVE: + chip->nchannels = ARRAY_SIZE(cp_slave_chans); rc = smb1390_slave_probe(chip); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + dev_err(chip->dev, "Couldn't probe SMB1390 slave rc= %d\n", + rc); + goto cleanup; + } + rc = cp_iio_probe_init(chip, indio_dev, cp_slave_chans, &cp_slave_iio_info); break; default: pr_err("Couldn't find a matching role %d\n", chip->cp_role); @@ -2101,8 +2379,26 @@ static int smb1390_probe(struct platform_device *pdev) if (rc < 0) { if (rc != -EPROBE_DEFER) - pr_err("Couldn't probe SMB1390 %s rc=%d\n", - chip->cp_role ? "Slave" : "Master", rc); + dev_err(chip->dev, "IIO init failed for %s rc= %d\n", + chip->cp_role ? "slave" : "master", rc); + goto cleanup; + } + + /* + * This configuration below is applicable to both + * master and slave. The individual channel + * configurations are done in master / slave + * iio_probe_init calls. + */ + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = chip->cp_iio_chan_ids; + indio_dev->num_channels = chip->nchannels; + + rc = devm_iio_device_register(&pdev->dev, indio_dev); + if (rc) { + pr_err("iio device register failed rc=%d\n", rc); goto cleanup; }