root/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2023, Linaro Ltd. All rights reserved.
 */

#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/usb/pd.h>
#include <linux/usb/tcpm.h>
#include "qcom_pmic_typec.h"
#include "qcom_pmic_typec_pdphy.h"

/* PD PHY register offsets and bit fields */
#define USB_PDPHY_MSG_CONFIG_REG        0x40
#define MSG_CONFIG_PORT_DATA_ROLE       BIT(3)
#define MSG_CONFIG_PORT_POWER_ROLE      BIT(2)
#define MSG_CONFIG_SPEC_REV_MASK        (BIT(1) | BIT(0))

#define USB_PDPHY_EN_CONTROL_REG        0x46
#define CONTROL_ENABLE                  BIT(0)

#define USB_PDPHY_RX_STATUS_REG         0x4A
#define RX_FRAME_TYPE                   (BIT(0) | BIT(1) | BIT(2))

#define USB_PDPHY_FRAME_FILTER_REG      0x4C
#define FRAME_FILTER_EN_HARD_RESET      BIT(5)
#define FRAME_FILTER_EN_SOP             BIT(0)

#define USB_PDPHY_TX_SIZE_REG           0x42
#define TX_SIZE_MASK                    0xF

#define USB_PDPHY_TX_CONTROL_REG        0x44
#define TX_CONTROL_RETRY_COUNT(n)       (((n) & 0x3) << 5)
#define TX_CONTROL_FRAME_TYPE(n)        (((n) & 0x7) << 2)
#define TX_CONTROL_FRAME_TYPE_CABLE_RESET       (0x1 << 2)
#define TX_CONTROL_SEND_SIGNAL          BIT(1)
#define TX_CONTROL_SEND_MSG             BIT(0)

#define USB_PDPHY_RX_SIZE_REG           0x48

#define USB_PDPHY_RX_ACKNOWLEDGE_REG    0x4B
#define RX_BUFFER_TOKEN                 BIT(0)

#define USB_PDPHY_BIST_MODE_REG         0x4E
#define BIST_MODE_MASK                  0xF
#define BIST_ENABLE                     BIT(7)
#define PD_MSG_BIST                     0x3
#define PD_BIST_TEST_DATA_MODE          0x8

#define USB_PDPHY_TX_BUFFER_HDR_REG     0x60
#define USB_PDPHY_TX_BUFFER_DATA_REG    0x62

#define USB_PDPHY_RX_BUFFER_REG         0x80

/* VDD regulator */
#define VDD_PDPHY_VOL_MIN               2800000 /* uV */
#define VDD_PDPHY_VOL_MAX               3300000 /* uV */
#define VDD_PDPHY_HPM_LOAD              3000    /* uA */

/* Message Spec Rev field */
#define PD_MSG_HDR_REV(hdr)             (((hdr) >> 6) & 3)

/* timers */
#define RECEIVER_RESPONSE_TIME          15      /* tReceiverResponse */
#define HARD_RESET_COMPLETE_TIME        5       /* tHardResetComplete */

/* Interrupt numbers */
#define PMIC_PDPHY_SIG_TX_IRQ           0x0
#define PMIC_PDPHY_SIG_RX_IRQ           0x1
#define PMIC_PDPHY_MSG_TX_IRQ           0x2
#define PMIC_PDPHY_MSG_RX_IRQ           0x3
#define PMIC_PDPHY_MSG_TX_FAIL_IRQ      0x4
#define PMIC_PDPHY_MSG_TX_DISCARD_IRQ   0x5
#define PMIC_PDPHY_MSG_RX_DISCARD_IRQ   0x6
#define PMIC_PDPHY_FR_SWAP_IRQ          0x7


struct pmic_typec_pdphy_irq_data {
        int                             virq;
        int                             irq;
        struct pmic_typec_pdphy         *pmic_typec_pdphy;
};

struct pmic_typec_pdphy {
        struct device                   *dev;
        struct tcpm_port                *tcpm_port;
        struct regmap                   *regmap;
        u32                             base;

        unsigned int                    nr_irqs;
        struct pmic_typec_pdphy_irq_data        *irq_data;

        struct work_struct              reset_work;
        struct work_struct              receive_work;
        struct regulator                *vdd_pdphy;
        spinlock_t                      lock;           /* Register atomicity */
};

static void qcom_pmic_typec_pdphy_reset_on(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        struct device *dev = pmic_typec_pdphy->dev;
        int ret;

        /* Terminate TX */
        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, 0);
        if (ret)
                goto err;

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_FRAME_FILTER_REG, 0);
        if (ret)
                goto err;

        return;
err:
        dev_err(dev, "pd_reset_on error\n");
}

static void qcom_pmic_typec_pdphy_reset_off(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        struct device *dev = pmic_typec_pdphy->dev;
        int ret;

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_FRAME_FILTER_REG,
                           FRAME_FILTER_EN_SOP | FRAME_FILTER_EN_HARD_RESET);
        if (ret)
                dev_err(dev, "pd_reset_off error\n");
}

static void qcom_pmic_typec_pdphy_sig_reset_work(struct work_struct *work)
{
        struct pmic_typec_pdphy *pmic_typec_pdphy = container_of(work, struct pmic_typec_pdphy,
                                                     reset_work);
        unsigned long flags;

        spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);

        qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy);
        qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy);

        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);

        tcpm_pd_hard_reset(pmic_typec_pdphy->tcpm_port);
}

static int
qcom_pmic_typec_pdphy_clear_tx_control_reg(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        struct device *dev = pmic_typec_pdphy->dev;
        unsigned int val;
        int ret;

        /* Clear TX control register */
        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, 0);
        if (ret)
                goto done;

        /* Perform readback to ensure sufficient delay for command to latch */
        ret = regmap_read(pmic_typec_pdphy->regmap,
                          pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, &val);

done:
        if (ret)
                dev_err(dev, "pd_clear_tx_control_reg: clear tx flag\n");

        return ret;
}

static int
qcom_pmic_typec_pdphy_pd_transmit_signal(struct pmic_typec_pdphy *pmic_typec_pdphy,
                                         enum tcpm_transmit_type type,
                                         unsigned int negotiated_rev)
{
        struct device *dev = pmic_typec_pdphy->dev;
        unsigned int val;
        unsigned long flags;
        int ret;

        spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);

        /* Clear TX control register */
        ret = qcom_pmic_typec_pdphy_clear_tx_control_reg(pmic_typec_pdphy);
        if (ret)
                goto done;

        val = TX_CONTROL_SEND_SIGNAL;
        if (negotiated_rev == PD_REV30)
                val |= TX_CONTROL_RETRY_COUNT(2);
        else
                val |= TX_CONTROL_RETRY_COUNT(3);

        if (type == TCPC_TX_CABLE_RESET || type == TCPC_TX_HARD_RESET)
                val |= TX_CONTROL_FRAME_TYPE(1);

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, val);

done:
        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);

        dev_vdbg(dev, "pd_transmit_signal: type %d negotiate_rev %d send %d\n",
                 type, negotiated_rev, ret);

        return ret;
}

static int
qcom_pmic_typec_pdphy_pd_transmit_payload(struct pmic_typec_pdphy *pmic_typec_pdphy,
                                          enum tcpm_transmit_type type,
                                          const struct pd_message *msg,
                                          unsigned int negotiated_rev)
{
        struct device *dev = pmic_typec_pdphy->dev;
        unsigned int val, hdr_len, txbuf_len, txsize_len;
        unsigned long flags;
        int ret;

        spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);

        hdr_len = sizeof(msg->header);
        txbuf_len = pd_header_cnt_le(msg->header) * 4;
        txsize_len = hdr_len + txbuf_len - 1;

        ret = regmap_read(pmic_typec_pdphy->regmap,
                          pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG,
                          &val);
        if (ret)
                goto done;

        if (val) {
                dev_err(dev, "pd_transmit_payload: RX message pending\n");
                ret = -EBUSY;
                goto done;
        }

        /* Clear TX control register */
        ret = qcom_pmic_typec_pdphy_clear_tx_control_reg(pmic_typec_pdphy);
        if (ret)
                goto done;

        /* Write message header sizeof(u16) to USB_PDPHY_TX_BUFFER_HDR_REG */
        ret = regmap_bulk_write(pmic_typec_pdphy->regmap,
                                pmic_typec_pdphy->base + USB_PDPHY_TX_BUFFER_HDR_REG,
                                &msg->header, hdr_len);
        if (ret)
                goto done;

        /* Write payload to USB_PDPHY_TX_BUFFER_DATA_REG for txbuf_len */
        if (txbuf_len) {
                ret = regmap_bulk_write(pmic_typec_pdphy->regmap,
                                        pmic_typec_pdphy->base + USB_PDPHY_TX_BUFFER_DATA_REG,
                                        &msg->payload, txbuf_len);
                if (ret)
                        goto done;
        }

        /* Write total length ((header + data) - 1) to USB_PDPHY_TX_SIZE_REG */
        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_TX_SIZE_REG,
                           txsize_len);
        if (ret)
                goto done;

        /* Clear TX control register */
        ret = qcom_pmic_typec_pdphy_clear_tx_control_reg(pmic_typec_pdphy);
        if (ret)
                goto done;

        /* Initiate transmit with retry count as indicated by PD revision */
        val = TX_CONTROL_FRAME_TYPE(type) | TX_CONTROL_SEND_MSG;
        if (pd_header_rev(msg->header) == PD_REV30)
                val |= TX_CONTROL_RETRY_COUNT(2);
        else
                val |= TX_CONTROL_RETRY_COUNT(3);

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_TX_CONTROL_REG, val);

done:
        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);

        if (ret) {
                dev_err(dev, "pd_transmit_payload: hdr %*ph data %*ph ret %d\n",
                        hdr_len, &msg->header, txbuf_len, &msg->payload, ret);
        }

        return ret;
}

static int qcom_pmic_typec_pdphy_pd_transmit(struct tcpc_dev *tcpc,
                                             enum tcpm_transmit_type type,
                                             const struct pd_message *msg,
                                             unsigned int negotiated_rev)
{
        struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
        struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        struct device *dev = pmic_typec_pdphy->dev;
        int ret;

        if (msg) {
                ret = qcom_pmic_typec_pdphy_pd_transmit_payload(pmic_typec_pdphy,
                                                                type, msg,
                                                                negotiated_rev);
        } else {
                ret = qcom_pmic_typec_pdphy_pd_transmit_signal(pmic_typec_pdphy,
                                                               type,
                                                               negotiated_rev);
        }

        if (ret)
                dev_dbg(dev, "pd_transmit: type %x result %d\n", type, ret);

        return ret;
}

static void qcom_pmic_typec_pdphy_pd_receive(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        struct device *dev = pmic_typec_pdphy->dev;
        struct pd_message msg;
        unsigned int size, rx_status;
        unsigned long flags;
        int ret;

        spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);

        ret = regmap_read(pmic_typec_pdphy->regmap,
                          pmic_typec_pdphy->base + USB_PDPHY_RX_SIZE_REG, &size);
        if (ret)
                goto done;

        /* Hardware requires +1 of the real read value to be passed */
        if (size < 1 || size > sizeof(msg.payload) + 1) {
                dev_dbg(dev, "pd_receive: invalid size %d\n", size);
                goto done;
        }

        size += 1;
        ret = regmap_read(pmic_typec_pdphy->regmap,
                          pmic_typec_pdphy->base + USB_PDPHY_RX_STATUS_REG,
                          &rx_status);

        if (ret)
                goto done;

        ret = regmap_bulk_read(pmic_typec_pdphy->regmap,
                               pmic_typec_pdphy->base + USB_PDPHY_RX_BUFFER_REG,
                               (u8 *)&msg, size);
        if (ret)
                goto done;

        /* Return ownership of RX buffer to hardware */
        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG, 0);

done:
        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);

        if (!ret) {
                dev_vdbg(dev, "pd_receive: handing %d bytes to tcpm\n", size);
                tcpm_pd_receive(pmic_typec_pdphy->tcpm_port, &msg, TCPC_TX_SOP);
        }
}

static irqreturn_t qcom_pmic_typec_pdphy_isr(int irq, void *dev_id)
{
        struct pmic_typec_pdphy_irq_data *irq_data = dev_id;
        struct pmic_typec_pdphy *pmic_typec_pdphy = irq_data->pmic_typec_pdphy;
        struct device *dev = pmic_typec_pdphy->dev;

        switch (irq_data->virq) {
        case PMIC_PDPHY_SIG_TX_IRQ:
                dev_err(dev, "isr: tx_sig\n");
                break;
        case PMIC_PDPHY_SIG_RX_IRQ:
                schedule_work(&pmic_typec_pdphy->reset_work);
                break;
        case PMIC_PDPHY_MSG_TX_IRQ:
                tcpm_pd_transmit_complete(pmic_typec_pdphy->tcpm_port,
                                          TCPC_TX_SUCCESS);
                break;
        case PMIC_PDPHY_MSG_RX_IRQ:
                qcom_pmic_typec_pdphy_pd_receive(pmic_typec_pdphy);
                break;
        case PMIC_PDPHY_MSG_TX_FAIL_IRQ:
                tcpm_pd_transmit_complete(pmic_typec_pdphy->tcpm_port,
                                          TCPC_TX_FAILED);
                break;
        case PMIC_PDPHY_MSG_TX_DISCARD_IRQ:
                tcpm_pd_transmit_complete(pmic_typec_pdphy->tcpm_port,
                                          TCPC_TX_DISCARDED);
                break;
        }

        return IRQ_HANDLED;
}

static int qcom_pmic_typec_pdphy_set_pd_rx(struct tcpc_dev *tcpc, bool on)
{
        struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
        struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        unsigned long flags;
        int ret;

        spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG, !on);

        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);

        dev_dbg(pmic_typec_pdphy->dev, "set_pd_rx: %s\n", str_on_off(on));

        return ret;
}

static int qcom_pmic_typec_pdphy_set_roles(struct tcpc_dev *tcpc, bool attached,
                                           enum typec_role power_role,
                                           enum typec_data_role data_role)
{
        struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
        struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        struct device *dev = pmic_typec_pdphy->dev;
        unsigned long flags;
        int ret;

        spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);

        ret = regmap_update_bits(pmic_typec_pdphy->regmap,
                                 pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG,
                                 MSG_CONFIG_PORT_DATA_ROLE |
                                 MSG_CONFIG_PORT_POWER_ROLE,
                                 (data_role == TYPEC_HOST ? MSG_CONFIG_PORT_DATA_ROLE : 0) |
                                 (power_role == TYPEC_SOURCE ? MSG_CONFIG_PORT_POWER_ROLE : 0));

        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);

        dev_dbg(dev, "pdphy_set_roles: data_role_host=%d power_role_src=%d\n",
                data_role, power_role);

        return ret;
}

static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        struct device *dev = pmic_typec_pdphy->dev;
        int ret;

        /* PD 2.0, DR=TYPEC_DEVICE, PR=TYPEC_SINK */
        ret = regmap_update_bits(pmic_typec_pdphy->regmap,
                                 pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG,
                                 MSG_CONFIG_SPEC_REV_MASK, PD_REV20);
        if (ret)
                goto done;

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 0);
        if (ret)
                goto done;

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG,
                           CONTROL_ENABLE);
        if (ret)
                goto done;

        qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy);
done:
        if (ret)
                dev_err(dev, "pdphy_enable fail %d\n", ret);

        return ret;
}

static int qcom_pmic_typec_pdphy_disable(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        int ret;

        qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy);

        ret = regmap_write(pmic_typec_pdphy->regmap,
                           pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 0);

        return ret;
}

static int pmic_typec_pdphy_reset(struct pmic_typec_pdphy *pmic_typec_pdphy)
{
        int ret;

        ret = qcom_pmic_typec_pdphy_disable(pmic_typec_pdphy);
        if (ret)
                goto done;

        usleep_range(400, 500);
        ret = qcom_pmic_typec_pdphy_enable(pmic_typec_pdphy);
done:
        return ret;
}

static int qcom_pmic_typec_pdphy_start(struct pmic_typec *tcpm,
                                       struct tcpm_port *tcpm_port)
{
        struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        int i;
        int ret;

        ret = regulator_enable(pmic_typec_pdphy->vdd_pdphy);
        if (ret)
                return ret;

        pmic_typec_pdphy->tcpm_port = tcpm_port;

        ret = pmic_typec_pdphy_reset(pmic_typec_pdphy);
        if (ret)
                goto err_disable_vdd_pdhy;

        for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++)
                enable_irq(pmic_typec_pdphy->irq_data[i].irq);

        return 0;

err_disable_vdd_pdhy:
        regulator_disable(pmic_typec_pdphy->vdd_pdphy);

        return ret;
}

static void qcom_pmic_typec_pdphy_stop(struct pmic_typec *tcpm)
{
        struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        int i;

        for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++)
                disable_irq(pmic_typec_pdphy->irq_data[i].irq);

        qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy);

        regulator_disable(pmic_typec_pdphy->vdd_pdphy);
}

int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev,
                                struct pmic_typec *tcpm,
                                const struct pmic_typec_pdphy_resources *res,
                                struct regmap *regmap,
                                u32 base)
{
        struct pmic_typec_pdphy *pmic_typec_pdphy;
        struct device *dev = &pdev->dev;
        struct pmic_typec_pdphy_irq_data *irq_data;
        int i, ret, irq;

        pmic_typec_pdphy = devm_kzalloc(dev, sizeof(*pmic_typec_pdphy), GFP_KERNEL);
        if (!pmic_typec_pdphy)
                return -ENOMEM;

        if (!res->nr_irqs || res->nr_irqs > PMIC_PDPHY_MAX_IRQS)
                return -EINVAL;

        irq_data = devm_kcalloc(dev, res->nr_irqs, sizeof(*irq_data),
                                GFP_KERNEL);
        if (!irq_data)
                return -ENOMEM;

        pmic_typec_pdphy->vdd_pdphy = devm_regulator_get(dev, "vdd-pdphy");
        if (IS_ERR(pmic_typec_pdphy->vdd_pdphy))
                return PTR_ERR(pmic_typec_pdphy->vdd_pdphy);

        pmic_typec_pdphy->dev = dev;
        pmic_typec_pdphy->base = base;
        pmic_typec_pdphy->regmap = regmap;
        pmic_typec_pdphy->nr_irqs = res->nr_irqs;
        pmic_typec_pdphy->irq_data = irq_data;
        spin_lock_init(&pmic_typec_pdphy->lock);
        INIT_WORK(&pmic_typec_pdphy->reset_work, qcom_pmic_typec_pdphy_sig_reset_work);

        for (i = 0; i < res->nr_irqs; i++, irq_data++) {
                irq = platform_get_irq_byname(pdev, res->irq_params[i].irq_name);
                if (irq < 0)
                        return irq;

                irq_data->pmic_typec_pdphy = pmic_typec_pdphy;
                irq_data->irq = irq;
                irq_data->virq = res->irq_params[i].virq;

                ret = devm_request_threaded_irq(dev, irq, NULL,
                                                qcom_pmic_typec_pdphy_isr,
                                                IRQF_ONESHOT | IRQF_NO_AUTOEN,
                                                res->irq_params[i].irq_name,
                                                irq_data);
                if (ret)
                        return ret;
        }

        tcpm->pmic_typec_pdphy = pmic_typec_pdphy;

        tcpm->tcpc.set_pd_rx = qcom_pmic_typec_pdphy_set_pd_rx;
        tcpm->tcpc.set_roles = qcom_pmic_typec_pdphy_set_roles;
        tcpm->tcpc.pd_transmit = qcom_pmic_typec_pdphy_pd_transmit;

        tcpm->pdphy_start = qcom_pmic_typec_pdphy_start;
        tcpm->pdphy_stop = qcom_pmic_typec_pdphy_stop;

        return 0;
}

const struct pmic_typec_pdphy_resources pm8150b_pdphy_res = {
        .irq_params = {
                {
                        .virq = PMIC_PDPHY_SIG_TX_IRQ,
                        .irq_name = "sig-tx",
                },
                {
                        .virq = PMIC_PDPHY_SIG_RX_IRQ,
                        .irq_name = "sig-rx",
                },
                {
                        .virq = PMIC_PDPHY_MSG_TX_IRQ,
                        .irq_name = "msg-tx",
                },
                {
                        .virq = PMIC_PDPHY_MSG_RX_IRQ,
                        .irq_name = "msg-rx",
                },
                {
                        .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ,
                        .irq_name = "msg-tx-failed",
                },
                {
                        .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ,
                        .irq_name = "msg-tx-discarded",
                },
                {
                        .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ,
                        .irq_name = "msg-rx-discarded",
                },
        },
        .nr_irqs = 7,
};