diff options
Diffstat (limited to 'drivers/spi/spi-hisi-sfc-v3xx.c')
-rw-r--r-- | drivers/spi/spi-hisi-sfc-v3xx.c | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index 4cf8fc80a7b7..e3b57252d075 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -7,6 +7,7 @@ #include <linux/acpi.h> #include <linux/bitops.h> +#include <linux/dmi.h> #include <linux/iopoll.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -17,6 +18,12 @@ #define HISI_SFC_V3XX_VERSION (0x1f8) #define HISI_SFC_V3XX_CMD_CFG (0x300) +#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17) +#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17) +#define HISI_SFC_V3XX_CMD_CFG_FULL_DIO (3 << 17) +#define HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT (5 << 17) +#define HISI_SFC_V3XX_CMD_CFG_QUAD_IO (6 << 17) +#define HISI_SFC_V3XX_CMD_CFG_FULL_QIO (7 << 17) #define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9 #define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8) #define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7) @@ -161,6 +168,43 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, if (op->addr.nbytes) config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK; + switch (op->data.buswidth) { + case 0 ... 1: + break; + case 2: + if (op->addr.buswidth <= 1) { + config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT; + } else if (op->addr.buswidth == 2) { + if (op->cmd.buswidth <= 1) { + config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IO; + } else if (op->cmd.buswidth == 2) { + config |= HISI_SFC_V3XX_CMD_CFG_FULL_DIO; + } else { + return -EIO; + } + } else { + return -EIO; + } + break; + case 4: + if (op->addr.buswidth <= 1) { + config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT; + } else if (op->addr.buswidth == 4) { + if (op->cmd.buswidth <= 1) { + config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IO; + } else if (op->cmd.buswidth == 4) { + config |= HISI_SFC_V3XX_CMD_CFG_FULL_QIO; + } else { + return -EIO; + } + } else { + return -EIO; + } + break; + default: + return -EOPNOTSUPP; + } + if (op->data.dir != SPI_MEM_NO_DATA) { config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF; config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK; @@ -207,6 +251,44 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = { .exec_op = hisi_sfc_v3xx_exec_op, }; +static int hisi_sfc_v3xx_buswidth_override_bits; + +/* + * ACPI FW does not allow us to currently set the device buswidth, so quirk it + * depending on the board. + */ +static int __init hisi_sfc_v3xx_dmi_quirk(const struct dmi_system_id *d) +{ + hisi_sfc_v3xx_buswidth_override_bits = SPI_RX_QUAD | SPI_TX_QUAD; + + return 0; +} + +static const struct dmi_system_id hisi_sfc_v3xx_dmi_quirk_table[] = { + { + .callback = hisi_sfc_v3xx_dmi_quirk, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Huawei"), + DMI_MATCH(DMI_PRODUCT_NAME, "D06"), + }, + }, + { + .callback = hisi_sfc_v3xx_dmi_quirk, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Huawei"), + DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 2280 V2"), + }, + }, + { + .callback = hisi_sfc_v3xx_dmi_quirk, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Huawei"), + DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 200 (Model 2280)"), + }, + }, + {} +}; + static int hisi_sfc_v3xx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -222,6 +304,8 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; + ctlr->buswidth_override_bits = hisi_sfc_v3xx_buswidth_override_bits; + host = spi_controller_get_devdata(ctlr); host->dev = dev; @@ -277,7 +361,20 @@ static struct platform_driver hisi_sfc_v3xx_spi_driver = { .probe = hisi_sfc_v3xx_probe, }; -module_platform_driver(hisi_sfc_v3xx_spi_driver); +static int __init hisi_sfc_v3xx_spi_init(void) +{ + dmi_check_system(hisi_sfc_v3xx_dmi_quirk_table); + + return platform_driver_register(&hisi_sfc_v3xx_spi_driver); +} + +static void __exit hisi_sfc_v3xx_spi_exit(void) +{ + platform_driver_unregister(&hisi_sfc_v3xx_spi_driver); +} + +module_init(hisi_sfc_v3xx_spi_init); +module_exit(hisi_sfc_v3xx_spi_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Garry <john.garry@huawei.com>"); |