usb: typec: ucsi: ccg: add get_fw_info function
authorAjay Gupta <ajayg@nvidia.com>
Tue, 23 Apr 2019 14:21:45 +0000 (17:21 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Apr 2019 09:03:52 +0000 (11:03 +0200)
Function is to get the details of ccg firmware and device version.
It will be useful in debugging and also during firmware update.

Signed-off-by: Ajay Gupta <ajayg@nvidia.com>
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/ucsi_ccg.c

index de8a43bdff6898169770439326d135f1a6cda30b..3884fb41c72e5007d93b0e6139425d012ce0ede9 100644 (file)
 #include <asm/unaligned.h>
 #include "ucsi.h"
 
+enum enum_fw_mode {
+       BOOT,   /* bootloader */
+       FW1,    /* FW partition-1 (contains secondary fw) */
+       FW2,    /* FW partition-2 (contains primary fw) */
+       FW_INVALID,
+};
+
+struct ccg_dev_info {
+#define CCG_DEVINFO_FWMODE_SHIFT (0)
+#define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
+#define CCG_DEVINFO_PDPORTS_SHIFT (2)
+#define CCG_DEVINFO_PDPORTS_MASK (0x3 << CCG_DEVINFO_PDPORTS_SHIFT)
+       u8 mode;
+       u8 bl_mode;
+       __le16 silicon_id;
+       __le16 bl_last_row;
+} __packed;
+
+struct version_format {
+       __le16 build;
+       u8 patch;
+       u8 ver;
+#define CCG_VERSION_MIN_SHIFT (0)
+#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
+#define CCG_VERSION_MAJ_SHIFT (4)
+#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
+} __packed;
+
+struct version_info {
+       struct version_format base;
+       struct version_format app;
+};
+
 struct ucsi_ccg {
        struct device *dev;
        struct ucsi *ucsi;
        struct ucsi_ppm ppm;
        struct i2c_client *client;
+       struct ccg_dev_info info;
+       /* version info for boot, primary and secondary */
+       struct version_info version[FW2 + 1];
 };
 
-#define CCGX_RAB_INTR_REG                      0x06
-#define CCGX_RAB_UCSI_CONTROL                  0x39
+#define CCGX_RAB_DEVICE_MODE                   0x0000
+#define CCGX_RAB_INTR_REG                      0x0006
+#define CCGX_RAB_READ_ALL_VER                  0x0010
+#define CCGX_RAB_READ_FW2_VER                  0x0020
+#define CCGX_RAB_UCSI_CONTROL                  0x0039
 #define CCGX_RAB_UCSI_CONTROL_START            BIT(0)
 #define CCGX_RAB_UCSI_CONTROL_STOP             BIT(1)
 #define CCGX_RAB_UCSI_DATA_BLOCK(offset)       (0xf000 | ((offset) & 0xff))
@@ -220,6 +259,23 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static int get_fw_info(struct ucsi_ccg *uc)
+{
+       int err;
+
+       err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&uc->version),
+                      sizeof(uc->version));
+       if (err < 0)
+               return err;
+
+       err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
+                      sizeof(uc->info));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 static int ucsi_ccg_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
@@ -248,6 +304,12 @@ static int ucsi_ccg_probe(struct i2c_client *client,
                return status;
        }
 
+       status = get_fw_info(uc);
+       if (status < 0) {
+               dev_err(uc->dev, "get_fw_info failed - %d\n", status);
+               return status;
+       }
+
        status = devm_request_threaded_irq(dev, client->irq, NULL,
                                           ccg_irq_handler,
                                           IRQF_ONESHOT | IRQF_TRIGGER_HIGH,