Merge "regulator: qpnp-labibb: Add support for notifier callback"

This commit is contained in:
Linux Build Service Account 2017-02-25 01:09:27 -08:00 committed by Gerrit - the friendly Code Review server
commit 8f0acd2665
3 changed files with 84 additions and 0 deletions

View file

@ -149,6 +149,8 @@ LAB subnode optional properties:
already. If it it not specified, then already. If it it not specified, then
output voltage can be configured to output voltage can be configured to
any value in the allowed limit. any value in the allowed limit.
- qcom,notify-lab-vreg-ok-sts: A boolean property which upon set will
poll and notify the lab_vreg_ok status.
Following properties are available only for PM660A: Following properties are available only for PM660A:

View file

@ -19,16 +19,19 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/spmi.h> #include <linux/spmi.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h> #include <linux/regulator/of_regulator.h>
#include <linux/qpnp/qpnp-revid.h> #include <linux/qpnp/qpnp-revid.h>
#include <linux/regulator/qpnp-labibb-regulator.h>
#define QPNP_LABIBB_REGULATOR_DRIVER_NAME "qcom,qpnp-labibb-regulator" #define QPNP_LABIBB_REGULATOR_DRIVER_NAME "qcom,qpnp-labibb-regulator"
@ -594,6 +597,7 @@ struct qpnp_labibb {
const struct lab_ver_ops *lab_ver_ops; const struct lab_ver_ops *lab_ver_ops;
struct mutex bus_mutex; struct mutex bus_mutex;
enum qpnp_labibb_mode mode; enum qpnp_labibb_mode mode;
struct work_struct lab_vreg_ok_work;
bool standalone; bool standalone;
bool ttw_en; bool ttw_en;
bool in_ttw_mode; bool in_ttw_mode;
@ -603,10 +607,13 @@ struct qpnp_labibb {
bool ttw_force_lab_on; bool ttw_force_lab_on;
bool skip_2nd_swire_cmd; bool skip_2nd_swire_cmd;
bool pfm_enable; bool pfm_enable;
bool notify_lab_vreg_ok_sts;
u32 swire_2nd_cmd_delay; u32 swire_2nd_cmd_delay;
u32 swire_ibb_ps_enable_delay; u32 swire_ibb_ps_enable_delay;
}; };
static RAW_NOTIFIER_HEAD(labibb_notifier);
struct ibb_ver_ops { struct ibb_ver_ops {
int (*set_default_voltage)(struct qpnp_labibb *labibb, int (*set_default_voltage)(struct qpnp_labibb *labibb,
bool use_default); bool use_default);
@ -2124,6 +2131,36 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb)
return rc; return rc;
} }
static void qpnp_lab_vreg_notifier_work(struct work_struct *work)
{
int rc = 0;
u16 retries = 1000, dly = 5000;
u8 val;
struct qpnp_labibb *labibb = container_of(work, struct qpnp_labibb,
lab_vreg_ok_work);
while (retries--) {
rc = qpnp_labibb_read(labibb, labibb->lab_base +
REG_LAB_STATUS1, &val, 1);
if (rc < 0) {
pr_err("read register %x failed rc = %d\n",
REG_LAB_STATUS1, rc);
return;
}
if (val & LAB_STATUS1_VREG_OK) {
raw_notifier_call_chain(&labibb_notifier,
LAB_VREG_OK, NULL);
break;
}
usleep_range(dly, dly + 100);
}
if (!retries)
pr_err("LAB_VREG_OK not set, failed to notify\n");
}
static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
{ {
int rc; int rc;
@ -2326,6 +2363,9 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev)
labibb->lab_vreg.vreg_enabled = 1; labibb->lab_vreg.vreg_enabled = 1;
} }
if (labibb->notify_lab_vreg_ok_sts)
schedule_work(&labibb->lab_vreg_ok_work);
return 0; return 0;
} }
@ -2578,6 +2618,9 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb,
return rc; return rc;
} }
labibb->notify_lab_vreg_ok_sts = of_property_read_bool(of_node,
"qcom,notify-lab-vreg-ok-sts");
rc = of_property_read_u32(of_node, "qcom,qpnp-lab-soft-start", rc = of_property_read_u32(of_node, "qcom,qpnp-lab-soft-start",
&(labibb->lab_vreg.soft_start)); &(labibb->lab_vreg.soft_start));
if (!rc) { if (!rc) {
@ -3817,6 +3860,8 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
goto fail_registration; goto fail_registration;
} }
} }
INIT_WORK(&labibb->lab_vreg_ok_work, qpnp_lab_vreg_notifier_work);
dev_set_drvdata(&pdev->dev, labibb); dev_set_drvdata(&pdev->dev, labibb);
pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n", pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n",
labibb->lab_vreg.vreg_enabled, labibb->lab_vreg.vreg_enabled,
@ -3834,6 +3879,18 @@ fail_registration:
return rc; return rc;
} }
int qpnp_labibb_notifier_register(struct notifier_block *nb)
{
return raw_notifier_chain_register(&labibb_notifier, nb);
}
EXPORT_SYMBOL(qpnp_labibb_notifier_register);
int qpnp_labibb_notifier_unregister(struct notifier_block *nb)
{
return raw_notifier_chain_unregister(&labibb_notifier, nb);
}
EXPORT_SYMBOL(qpnp_labibb_notifier_unregister);
static int qpnp_labibb_regulator_remove(struct platform_device *pdev) static int qpnp_labibb_regulator_remove(struct platform_device *pdev)
{ {
struct qpnp_labibb *labibb = dev_get_drvdata(&pdev->dev); struct qpnp_labibb *labibb = dev_get_drvdata(&pdev->dev);
@ -3843,6 +3900,8 @@ static int qpnp_labibb_regulator_remove(struct platform_device *pdev)
regulator_unregister(labibb->lab_vreg.rdev); regulator_unregister(labibb->lab_vreg.rdev);
if (labibb->ibb_vreg.rdev) if (labibb->ibb_vreg.rdev)
regulator_unregister(labibb->ibb_vreg.rdev); regulator_unregister(labibb->ibb_vreg.rdev);
cancel_work_sync(&labibb->lab_vreg_ok_work);
} }
return 0; return 0;
} }

View file

@ -0,0 +1,23 @@
/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef _QPNP_LABIBB_REGULATOR_H
#define _QPNP_LABIBB_REGULATOR_H
enum labibb_notify_event {
LAB_VREG_OK = 1,
};
int qpnp_labibb_notifier_register(struct notifier_block *nb);
int qpnp_labibb_notifier_unregister(struct notifier_block *nb);
#endif