/** * pa_write_data: write 1..4 bytes from buf to pmic-arb's register * @bc: byte-count -1. range: 0..3. * @reg: register's address. * @buf: buffer to write. length must be bc + 1. */ static void pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc) { u32 data = 0; memcpy(&data, buf, (bc & 3) + 1); pmic_arb_base_write(dev, reg, data); }
static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u16 addr, const u8 *buf, size_t len) { struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); unsigned long flags; u8 bc = len - 1; u32 cmd; int rc; u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, addr); if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", PMIC_ARB_MAX_TRANS_BYTES, len); return -EINVAL; } /* Check the opcode */ if (opc >= 0x40 && opc <= 0x5F) opc = PMIC_ARB_OP_WRITE; else if (opc >= 0x00 && opc <= 0x0F) opc = PMIC_ARB_OP_EXT_WRITE; else if (opc >= 0x30 && opc <= 0x37) opc = PMIC_ARB_OP_EXT_WRITEL; else if (opc >= 0x80 && opc <= 0xFF) opc = PMIC_ARB_OP_ZERO_WRITE; else return -EINVAL; cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); /* Write data to FIFOs */ raw_spin_lock_irqsave(&pmic_arb->lock, flags); pa_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0, min_t(u8, bc, 3)); if (bc > 3) pa_write_data(pmic_arb, buf + 4, offset + PMIC_ARB_WDATA1, bc - 4); /* Start the transaction */ pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr); raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); return rc; }
static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u16 addr, u8 *buf, size_t len) { struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); unsigned long flags; u8 bc = len - 1; u32 cmd; int rc; if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but %d requested", PMIC_ARB_MAX_TRANS_BYTES, len); return -EINVAL; } /* Check the opcode */ if (opc >= 0x60 && opc <= 0x7F) opc = PMIC_ARB_OP_READ; else if (opc >= 0x20 && opc <= 0x2F) opc = PMIC_ARB_OP_EXT_READ; else if (opc >= 0x38 && opc <= 0x3F) opc = PMIC_ARB_OP_EXT_READL; else return -EINVAL; cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); rc = pmic_arb_wait_for_done(ctrl); if (rc) goto done; pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel), min_t(u8, bc, 3)); if (bc > 3) pa_read_data(pmic_arb, buf + 4, PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4); done: raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); return rc; }
static int pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid) { struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); unsigned long flags; u32 cmd; int rc; u32 offset = pmic_arb->ver_ops->offset(pmic_arb, sid, 0); cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0); raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); return rc; }
/* Non-data command */ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) { struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); unsigned long flags; u32 cmd; int rc; /* Check for valid non-data command */ if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) return -EINVAL; cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); rc = pmic_arb_wait_for_done(ctrl); raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); return rc; }