summaryrefslogtreecommitdiff
path: root/drivers/spmi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spmi')
-rw-r--r--drivers/spmi/Makefile2
-rw-r--r--drivers/spmi/hisi-spmi-controller.c32
-rw-r--r--drivers/spmi/spmi-devres.c64
-rw-r--r--drivers/spmi/spmi-mtk-pmif.c61
-rw-r--r--drivers/spmi/spmi-pmic-arb.c87
-rw-r--r--drivers/spmi/spmi.c6
6 files changed, 143 insertions, 109 deletions
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 9d974424c8c1..7f152167bb05 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -2,7 +2,7 @@
#
# Makefile for kernel SPMI framework.
#
-obj-$(CONFIG_SPMI) += spmi.o
+obj-$(CONFIG_SPMI) += spmi.o spmi-devres.o
obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 9cbd473487cb..674a350cc676 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -267,10 +267,10 @@ static int spmi_controller_probe(struct platform_device *pdev)
struct resource *iores;
int ret;
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
- if (!ctrl) {
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
+ if (IS_ERR(ctrl)) {
dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
- return -ENOMEM;
+ return PTR_ERR(ctrl);
}
spmi_controller = spmi_controller_get_drvdata(ctrl);
spmi_controller->controller = ctrl;
@@ -278,24 +278,21 @@ static int spmi_controller_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iores) {
dev_err(&pdev->dev, "can not get resource!\n");
- ret = -EINVAL;
- goto err_put_controller;
+ return -EINVAL;
}
spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
resource_size(iores));
if (!spmi_controller->base) {
dev_err(&pdev->dev, "can not remap base addr!\n");
- ret = -EADDRNOTAVAIL;
- goto err_put_controller;
+ return -EADDRNOTAVAIL;
}
ret = of_property_read_u32(pdev->dev.of_node, "hisilicon,spmi-channel",
&spmi_controller->channel);
if (ret) {
dev_err(&pdev->dev, "can not get channel\n");
- ret = -ENODEV;
- goto err_put_controller;
+ return -ENODEV;
}
platform_set_drvdata(pdev, spmi_controller);
@@ -311,25 +308,13 @@ static int spmi_controller_probe(struct platform_device *pdev)
ctrl->read_cmd = spmi_read_cmd;
ctrl->write_cmd = spmi_write_cmd;
- ret = spmi_controller_add(ctrl);
+ ret = devm_spmi_controller_add(&pdev->dev, ctrl);
if (ret) {
dev_err(&pdev->dev, "spmi_controller_add failed with error %d!\n", ret);
- goto err_put_controller;
+ return ret;
}
return 0;
-
-err_put_controller:
- spmi_controller_put(ctrl);
- return ret;
-}
-
-static void spmi_del_controller(struct platform_device *pdev)
-{
- struct spmi_controller *ctrl = platform_get_drvdata(pdev);
-
- spmi_controller_remove(ctrl);
- spmi_controller_put(ctrl);
}
static const struct of_device_id spmi_controller_match_table[] = {
@@ -342,7 +327,6 @@ MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
static struct platform_driver spmi_controller_driver = {
.probe = spmi_controller_probe,
- .remove_new = spmi_del_controller,
.driver = {
.name = "hisi_spmi_controller",
.of_match_table = spmi_controller_match_table,
diff --git a/drivers/spmi/spmi-devres.c b/drivers/spmi/spmi-devres.c
new file mode 100644
index 000000000000..62c4b3f24d06
--- /dev/null
+++ b/drivers/spmi/spmi-devres.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Google LLC.
+ */
+
+#include <linux/device.h>
+#include <linux/spmi.h>
+
+static void devm_spmi_controller_release(struct device *parent, void *res)
+{
+ spmi_controller_put(*(struct spmi_controller **)res);
+}
+
+struct spmi_controller *devm_spmi_controller_alloc(struct device *parent, size_t size)
+{
+ struct spmi_controller **ptr, *ctrl;
+
+ ptr = devres_alloc(devm_spmi_controller_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ ctrl = spmi_controller_alloc(parent, size);
+ if (IS_ERR(ctrl)) {
+ devres_free(ptr);
+ return ctrl;
+ }
+
+ *ptr = ctrl;
+ devres_add(parent, ptr);
+
+ return ctrl;
+}
+EXPORT_SYMBOL_GPL(devm_spmi_controller_alloc);
+
+static void devm_spmi_controller_remove(struct device *parent, void *res)
+{
+ spmi_controller_remove(*(struct spmi_controller **)res);
+}
+
+int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl)
+{
+ struct spmi_controller **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_spmi_controller_remove, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = spmi_controller_add(ctrl);
+ if (ret) {
+ devres_free(ptr);
+ return ret;
+ }
+
+ *ptr = ctrl;
+ devres_add(parent, ptr);
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(devm_spmi_controller_add);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SPMI devres helpers");
diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c
index b3c991e1ea40..5079442f8ea1 100644
--- a/drivers/spmi/spmi-mtk-pmif.c
+++ b/drivers/spmi/spmi-mtk-pmif.c
@@ -50,6 +50,7 @@ struct pmif {
struct clk_bulk_data clks[PMIF_MAX_CLKS];
size_t nclks;
const struct pmif_data *data;
+ raw_spinlock_t lock;
};
static const char * const pmif_clock_names[] = {
@@ -314,6 +315,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
struct ch_reg *inf_reg;
int ret;
u32 data, cmd;
+ unsigned long flags;
/* Check for argument validation. */
if (sid & ~0xf) {
@@ -334,6 +336,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
else
return -EINVAL;
+ raw_spin_lock_irqsave(&arb->lock, flags);
/* Wait for Software Interface FSM state to be IDLE. */
inf_reg = &arb->chan;
ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
@@ -343,6 +346,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* set channel ready if the data has transferred */
if (pmif_is_fsm_vldclr(arb))
pmif_writel(arb, 1, inf_reg->ch_rdy);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
return ret;
}
@@ -350,6 +354,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* Send the command. */
cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
pmif_writel(arb, cmd, inf_reg->ch_send);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
/*
* Wait for Software Interface FSM state to be WFVLDCLR,
@@ -376,7 +381,14 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
struct pmif *arb = spmi_controller_get_drvdata(ctrl);
struct ch_reg *inf_reg;
int ret;
- u32 data, cmd;
+ u32 data, wdata, cmd;
+ unsigned long flags;
+
+ /* Check for argument validation. */
+ if (unlikely(sid & ~0xf)) {
+ dev_err(&ctrl->dev, "exceed the max slv id\n");
+ return -EINVAL;
+ }
if (len > 4) {
dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
@@ -394,6 +406,10 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
else
return -EINVAL;
+ /* Set the write data. */
+ memcpy(&wdata, buf, len);
+
+ raw_spin_lock_irqsave(&arb->lock, flags);
/* Wait for Software Interface FSM state to be IDLE. */
inf_reg = &arb->chan;
ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
@@ -403,17 +419,17 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* set channel ready if the data has transferred */
if (pmif_is_fsm_vldclr(arb))
pmif_writel(arb, 1, inf_reg->ch_rdy);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
return ret;
}
- /* Set the write data. */
- memcpy(&data, buf, len);
- pmif_writel(arb, data, inf_reg->wdata);
+ pmif_writel(arb, wdata, inf_reg->wdata);
/* Send the command. */
cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;
pmif_writel(arb, cmd, inf_reg->ch_send);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
return 0;
}
@@ -437,44 +453,39 @@ static int mtk_spmi_probe(struct platform_device *pdev)
int err, i;
u32 chan_offset;
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*arb));
- if (!ctrl)
- return -ENOMEM;
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*arb));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
arb = spmi_controller_get_drvdata(ctrl);
arb->data = device_get_match_data(&pdev->dev);
if (!arb->data) {
- err = -EINVAL;
dev_err(&pdev->dev, "Cannot get drv_data\n");
- goto err_put_ctrl;
+ return -EINVAL;
}
arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");
- if (IS_ERR(arb->base)) {
- err = PTR_ERR(arb->base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(arb->base))
+ return PTR_ERR(arb->base);
arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");
- if (IS_ERR(arb->spmimst_base)) {
- err = PTR_ERR(arb->spmimst_base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(arb->spmimst_base))
+ return PTR_ERR(arb->spmimst_base);
arb->nclks = ARRAY_SIZE(pmif_clock_names);
for (i = 0; i < arb->nclks; i++)
arb->clks[i].id = pmif_clock_names[i];
- err = devm_clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
+ err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
if (err) {
dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
- goto err_put_ctrl;
+ return err;
}
err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
if (err) {
dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
- goto err_put_ctrl;
+ goto err_put_clks;
}
ctrl->cmd = pmif_arb_cmd;
@@ -488,6 +499,8 @@ static int mtk_spmi_probe(struct platform_device *pdev)
arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;
arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;
+ raw_spin_lock_init(&arb->lock);
+
platform_set_drvdata(pdev, ctrl);
err = spmi_controller_add(ctrl);
@@ -498,8 +511,8 @@ static int mtk_spmi_probe(struct platform_device *pdev)
err_domain_remove:
clk_bulk_disable_unprepare(arb->nclks, arb->clks);
-err_put_ctrl:
- spmi_controller_put(ctrl);
+err_put_clks:
+ clk_bulk_put(arb->nclks, arb->clks);
return err;
}
@@ -508,9 +521,9 @@ static void mtk_spmi_remove(struct platform_device *pdev)
struct spmi_controller *ctrl = platform_get_drvdata(pdev);
struct pmif *arb = spmi_controller_get_drvdata(ctrl);
- clk_bulk_disable_unprepare(arb->nclks, arb->clks);
spmi_controller_remove(ctrl);
- spmi_controller_put(ctrl);
+ clk_bulk_disable_unprepare(arb->nclks, arb->clks);
+ clk_bulk_put(arb->nclks, arb->clks);
}
static const struct of_device_id mtk_spmi_match_table[] = {
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index dcb675d980d4..9ed1180fe31f 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1443,9 +1443,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
u32 channel, ee, hw_ver;
int err;
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
- if (!ctrl)
- return -ENOMEM;
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
pmic_arb = spmi_controller_get_drvdata(ctrl);
pmic_arb->spmic = ctrl;
@@ -1462,20 +1462,16 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
*/
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
- if (IS_ERR(core)) {
- err = PTR_ERR(core);
- goto err_put_ctrl;
- }
+ if (IS_ERR(core))
+ return PTR_ERR(core);
pmic_arb->core_size = resource_size(res);
pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID,
sizeof(*pmic_arb->ppid_to_apid),
GFP_KERNEL);
- if (!pmic_arb->ppid_to_apid) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!pmic_arb->ppid_to_apid)
+ return -ENOMEM;
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
@@ -1499,19 +1495,15 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
"obsrvr");
pmic_arb->rd_base = devm_ioremap(&ctrl->dev, res->start,
resource_size(res));
- if (IS_ERR(pmic_arb->rd_base)) {
- err = PTR_ERR(pmic_arb->rd_base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->rd_base))
+ return PTR_ERR(pmic_arb->rd_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"chnls");
pmic_arb->wr_base = devm_ioremap(&ctrl->dev, res->start,
resource_size(res));
- if (IS_ERR(pmic_arb->wr_base)) {
- err = PTR_ERR(pmic_arb->wr_base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->wr_base))
+ return PTR_ERR(pmic_arb->wr_base);
}
pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
@@ -1522,10 +1514,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
of_property_read_u32(pdev->dev.of_node, "qcom,bus-id",
&pmic_arb->bus_instance);
if (pmic_arb->bus_instance > 1) {
- err = -EINVAL;
dev_err(&pdev->dev, "invalid bus instance (%u) specified\n",
pmic_arb->bus_instance);
- goto err_put_ctrl;
+ return -EINVAL;
}
if (pmic_arb->bus_instance == 0) {
@@ -1543,10 +1534,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
}
if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
- err = -EINVAL;
dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
pmic_arb->base_apid + pmic_arb->apid_count);
- goto err_put_ctrl;
+ return -EINVAL;
}
} else if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
pmic_arb->base_apid = 0;
@@ -1554,55 +1544,45 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
PMIC_ARB_FEATURES_PERIPH_MASK;
if (pmic_arb->apid_count > pmic_arb->max_periphs) {
- err = -EINVAL;
dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
pmic_arb->apid_count);
- goto err_put_ctrl;
+ return -EINVAL;
}
}
pmic_arb->apid_data = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
sizeof(*pmic_arb->apid_data),
GFP_KERNEL);
- if (!pmic_arb->apid_data) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!pmic_arb->apid_data)
+ return -ENOMEM;
dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
pmic_arb->ver_ops->ver_str, hw_ver);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
- if (IS_ERR(pmic_arb->intr)) {
- err = PTR_ERR(pmic_arb->intr);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->intr))
+ return PTR_ERR(pmic_arb->intr);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res);
- if (IS_ERR(pmic_arb->cnfg)) {
- err = PTR_ERR(pmic_arb->cnfg);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->cnfg))
+ return PTR_ERR(pmic_arb->cnfg);
pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq");
- if (pmic_arb->irq < 0) {
- err = pmic_arb->irq;
- goto err_put_ctrl;
- }
+ if (pmic_arb->irq < 0)
+ return pmic_arb->irq;
err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
if (err) {
dev_err(&pdev->dev, "channel unspecified.\n");
- goto err_put_ctrl;
+ return err;
}
if (channel > 5) {
dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
channel);
- err = -EINVAL;
- goto err_put_ctrl;
+ return -EINVAL;
}
pmic_arb->channel = channel;
@@ -1610,22 +1590,19 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee);
if (err) {
dev_err(&pdev->dev, "EE unspecified.\n");
- goto err_put_ctrl;
+ return err;
}
if (ee > 5) {
dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee);
- err = -EINVAL;
- goto err_put_ctrl;
+ return -EINVAL;
}
pmic_arb->ee = ee;
mapping_table = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
sizeof(*mapping_table), GFP_KERNEL);
- if (!mapping_table) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!mapping_table)
+ return -ENOMEM;
pmic_arb->mapping_table = mapping_table;
/* Initialize max_apid/min_apid to the opposite bounds, during
@@ -1645,7 +1622,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
if (err) {
dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n",
err);
- goto err_put_ctrl;
+ return err;
}
}
@@ -1654,8 +1631,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
&pmic_arb_irq_domain_ops, pmic_arb);
if (!pmic_arb->domain) {
dev_err(&pdev->dev, "unable to create irq_domain\n");
- err = -ENOMEM;
- goto err_put_ctrl;
+ return -ENOMEM;
}
irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq,
@@ -1669,8 +1645,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
err_domain_remove:
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
irq_domain_remove(pmic_arb->domain);
-err_put_ctrl:
- spmi_controller_put(ctrl);
return err;
}
@@ -1681,7 +1655,6 @@ static void spmi_pmic_arb_remove(struct platform_device *pdev)
spmi_controller_remove(ctrl);
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
irq_domain_remove(pmic_arb->domain);
- spmi_controller_put(ctrl);
}
static const struct of_device_id spmi_pmic_arb_match_table[] = {
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 93cd4a34debc..3a60fd2e09e1 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -448,11 +448,11 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
int id;
if (WARN_ON(!parent))
- return NULL;
+ return ERR_PTR(-EINVAL);
ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
if (!ctrl)
- return NULL;
+ return ERR_PTR(-ENOMEM);
device_initialize(&ctrl->dev);
ctrl->dev.type = &spmi_ctrl_type;
@@ -466,7 +466,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
dev_err(parent,
"unable to allocate SPMI controller identifier.\n");
spmi_controller_put(ctrl);
- return NULL;
+ return ERR_PTR(id);
}
ctrl->nr = id;