mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Merge tag 'spmi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi
Pull SPMI updates from Stephen Boyd: "Support for Qualcomm PMIC arbiter v8.5 and Hawi along with a kernel doc cleanup and a kzalloc flex usage" * tag 'spmi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi: spmi: use kzalloc_flex in main allocation spmi: clean up kernel-doc in spmi.h spmi: spmi-pmic-arb: add support for PMIC arbiter v8.5 dt-bindings: spmi: glymur-spmi-pmic-arb: Add compatible for Qualcomm Hawi SoC
This commit is contained in:
@@ -25,6 +25,7 @@ properties:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,hawi-spmi-pmic-arb
|
||||
- qcom,kaanapali-spmi-pmic-arb
|
||||
- const: qcom,glymur-spmi-pmic-arb
|
||||
- enum:
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define PMIC_ARB_VERSION_V5_MIN 0x50000000
|
||||
#define PMIC_ARB_VERSION_V7_MIN 0x70000000
|
||||
#define PMIC_ARB_VERSION_V8_MIN 0x80000000
|
||||
#define PMIC_ARB_VERSION_V8P5_MIN 0x80050000
|
||||
#define PMIC_ARB_INT_EN 0x0004
|
||||
|
||||
#define PMIC_ARB_FEATURES 0x0004
|
||||
@@ -62,14 +63,6 @@
|
||||
/* Ownership Table */
|
||||
#define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
|
||||
|
||||
/* Channel Status fields */
|
||||
enum pmic_arb_chnl_status {
|
||||
PMIC_ARB_STATUS_DONE = BIT(0),
|
||||
PMIC_ARB_STATUS_FAILURE = BIT(1),
|
||||
PMIC_ARB_STATUS_DENIED = BIT(2),
|
||||
PMIC_ARB_STATUS_DROPPED = BIT(3),
|
||||
};
|
||||
|
||||
/* Command register fields */
|
||||
#define PMIC_ARB_CMD_MAX_BYTE_COUNT 8
|
||||
|
||||
@@ -239,6 +232,7 @@ struct spmi_pmic_arb {
|
||||
* on v2 address of SPMI_PIC_IRQ_CLEARn.
|
||||
* @apid_map_offset: offset of PMIC_ARB_REG_CHNLn
|
||||
* @apid_owner: on v2 and later address of SPMI_PERIPHn_2OWNER_TABLE_REG
|
||||
* @check_chnl_status: checks channel status and returns error code if any
|
||||
*/
|
||||
struct pmic_arb_ver_ops {
|
||||
const char *ver_str;
|
||||
@@ -261,6 +255,8 @@ struct pmic_arb_ver_ops {
|
||||
void __iomem *(*irq_clear)(struct spmi_pmic_arb_bus *bus, u16 n);
|
||||
u32 (*apid_map_offset)(u16 n);
|
||||
void __iomem *(*apid_owner)(struct spmi_pmic_arb_bus *bus, u16 n);
|
||||
int (*check_chnl_status)(struct spmi_controller *ctrl, u32 status,
|
||||
u8 sid, u16 addr, u32 offset);
|
||||
};
|
||||
|
||||
static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
|
||||
@@ -306,6 +302,84 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf,
|
||||
__raw_writel(data, pmic_arb->wr_base + reg);
|
||||
}
|
||||
|
||||
static int pmic_arb_check_chnl_status_v1(struct spmi_controller *ctrl,
|
||||
u32 status, u8 sid, u16 addr,
|
||||
u32 offset)
|
||||
{
|
||||
/* Check if DONE bit is set */
|
||||
if (!(status & BIT(0)))
|
||||
return -EAGAIN;
|
||||
|
||||
if (status & BIT(1)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
|
||||
__func__, sid, addr, status, offset);
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & BIT(2)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (status & BIT(3)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic_arb_check_chnl_status_v8p5(struct spmi_controller *ctrl,
|
||||
u32 status, u8 sid, u16 addr,
|
||||
u32 offset)
|
||||
{
|
||||
/* Check if DONE bit is set */
|
||||
if (!(status & BIT(0)))
|
||||
return -EAGAIN;
|
||||
|
||||
if (status & BIT(1)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
|
||||
__func__, sid, addr, status, offset);
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & BIT(2)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: CRC error (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & BIT(3)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: parity error (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & BIT(4)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: NACK error (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & BIT(5)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (status & BIT(6)) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
|
||||
void __iomem *base, u8 sid, u16 addr,
|
||||
enum pmic_arb_channel ch_type)
|
||||
@@ -327,28 +401,10 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
|
||||
while (timeout--) {
|
||||
status = readl_relaxed(base + offset);
|
||||
|
||||
if (status & PMIC_ARB_STATUS_DONE) {
|
||||
if (status & PMIC_ARB_STATUS_DENIED) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EPERM;
|
||||
}
|
||||
rc = pmic_arb->ver_ops->check_chnl_status(ctrl, status, sid, addr, offset);
|
||||
if (rc != -EAGAIN)
|
||||
return rc;
|
||||
|
||||
if (status & PMIC_ARB_STATUS_FAILURE) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
|
||||
__func__, sid, addr, status, offset);
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (status & PMIC_ARB_STATUS_DROPPED) {
|
||||
dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n",
|
||||
__func__, sid, addr, status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
@@ -1768,6 +1824,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
|
||||
.irq_clear = pmic_arb_irq_clear_v1,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v2,
|
||||
.apid_owner = pmic_arb_apid_owner_v2,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v1,
|
||||
};
|
||||
|
||||
static const struct pmic_arb_ver_ops pmic_arb_v2 = {
|
||||
@@ -1784,6 +1841,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = {
|
||||
.irq_clear = pmic_arb_irq_clear_v2,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v2,
|
||||
.apid_owner = pmic_arb_apid_owner_v2,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v1,
|
||||
};
|
||||
|
||||
static const struct pmic_arb_ver_ops pmic_arb_v3 = {
|
||||
@@ -1800,6 +1858,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = {
|
||||
.irq_clear = pmic_arb_irq_clear_v2,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v2,
|
||||
.apid_owner = pmic_arb_apid_owner_v2,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v1,
|
||||
};
|
||||
|
||||
static const struct pmic_arb_ver_ops pmic_arb_v5 = {
|
||||
@@ -1816,6 +1875,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
|
||||
.irq_clear = pmic_arb_irq_clear_v5,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v5,
|
||||
.apid_owner = pmic_arb_apid_owner_v2,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v1,
|
||||
};
|
||||
|
||||
static const struct pmic_arb_ver_ops pmic_arb_v7 = {
|
||||
@@ -1832,6 +1892,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v7 = {
|
||||
.irq_clear = pmic_arb_irq_clear_v7,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v7,
|
||||
.apid_owner = pmic_arb_apid_owner_v7,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v1,
|
||||
};
|
||||
|
||||
static const struct pmic_arb_ver_ops pmic_arb_v8 = {
|
||||
@@ -1849,6 +1910,25 @@ static const struct pmic_arb_ver_ops pmic_arb_v8 = {
|
||||
.irq_clear = pmic_arb_irq_clear_v8,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v8,
|
||||
.apid_owner = pmic_arb_apid_owner_v8,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v1,
|
||||
};
|
||||
|
||||
static const struct pmic_arb_ver_ops pmic_arb_v8p5 = {
|
||||
.ver_str = "v8.5",
|
||||
.get_core_resources = pmic_arb_get_core_resources_v8,
|
||||
.get_bus_resources = pmic_arb_get_bus_resources_v8,
|
||||
.init_apid = pmic_arb_init_apid_v8,
|
||||
.ppid_to_apid = pmic_arb_ppid_to_apid_v5,
|
||||
.non_data_cmd = pmic_arb_non_data_cmd_v2,
|
||||
.offset = pmic_arb_offset_v8,
|
||||
.fmt_cmd = pmic_arb_fmt_cmd_v2,
|
||||
.owner_acc_status = pmic_arb_owner_acc_status_v7,
|
||||
.acc_enable = pmic_arb_acc_enable_v8,
|
||||
.irq_status = pmic_arb_irq_status_v8,
|
||||
.irq_clear = pmic_arb_irq_clear_v8,
|
||||
.apid_map_offset = pmic_arb_apid_map_offset_v8,
|
||||
.apid_owner = pmic_arb_apid_owner_v8,
|
||||
.check_chnl_status = pmic_arb_check_chnl_status_v8p5,
|
||||
};
|
||||
|
||||
static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
|
||||
@@ -2030,8 +2110,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
|
||||
pmic_arb->ver_ops = &pmic_arb_v5;
|
||||
else if (hw_ver < PMIC_ARB_VERSION_V8_MIN)
|
||||
pmic_arb->ver_ops = &pmic_arb_v7;
|
||||
else
|
||||
else if (hw_ver < PMIC_ARB_VERSION_V8P5_MIN)
|
||||
pmic_arb->ver_ops = &pmic_arb_v8;
|
||||
else
|
||||
pmic_arb->ver_ops = &pmic_arb_v8p5;
|
||||
|
||||
err = pmic_arb->ver_ops->get_core_resources(pdev, core);
|
||||
if (err)
|
||||
|
||||
@@ -450,7 +450,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
|
||||
if (WARN_ON(!parent))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
|
||||
ctrl = kzalloc_flex(*ctrl, priv, size);
|
||||
if (!ctrl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -459,7 +459,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
|
||||
ctrl->dev.bus = &spmi_bus_type;
|
||||
ctrl->dev.parent = parent;
|
||||
ctrl->dev.of_node = parent->of_node;
|
||||
spmi_controller_set_drvdata(ctrl, &ctrl[1]);
|
||||
spmi_controller_set_drvdata(ctrl, ctrl->priv);
|
||||
|
||||
id = ida_alloc(&ctrl_ida, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
|
||||
@@ -76,6 +76,7 @@ void spmi_device_remove(struct spmi_device *sdev);
|
||||
* @cmd: sends a non-data command sequence on the SPMI bus.
|
||||
* @read_cmd: sends a register read command sequence on the SPMI bus.
|
||||
* @write_cmd: sends a register write command sequence on the SPMI bus.
|
||||
* @priv: array of private data.
|
||||
*/
|
||||
struct spmi_controller {
|
||||
struct device dev;
|
||||
@@ -85,6 +86,7 @@ struct spmi_controller {
|
||||
u8 sid, u16 addr, u8 *buf, size_t len);
|
||||
int (*write_cmd)(struct spmi_controller *ctrl, u8 opcode,
|
||||
u8 sid, u16 addr, const u8 *buf, size_t len);
|
||||
u8 priv[];
|
||||
};
|
||||
|
||||
static inline struct spmi_controller *to_spmi_controller(struct device *d)
|
||||
@@ -109,7 +111,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
|
||||
|
||||
/**
|
||||
* spmi_controller_put() - decrement controller refcount
|
||||
* @ctrl SPMI controller.
|
||||
* @ctrl: SPMI controller.
|
||||
*/
|
||||
static inline void spmi_controller_put(struct spmi_controller *ctrl)
|
||||
{
|
||||
@@ -129,6 +131,7 @@ int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl
|
||||
* this structure.
|
||||
* @probe: binds this driver to a SPMI device.
|
||||
* @remove: unbinds this driver from the SPMI device.
|
||||
* @shutdown: shuts down this driver.
|
||||
*
|
||||
* If PM runtime support is desired for a slave, a device driver can call
|
||||
* pm_runtime_put() from their probe() routine (and a balancing
|
||||
|
||||
Reference in New Issue
Block a user