0001
0002
0003
0004
0005
0006
0007 #include <linux/acpi.h>
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/kernel.h>
0014 #include "tpm.h"
0015 #include "tpm_tis_core.h"
0016
0017
0018
0019
0020
0021
0022 struct tpm_tis_synquacer_info {
0023 struct resource res;
0024 int irq;
0025 };
0026
0027 struct tpm_tis_synquacer_phy {
0028 struct tpm_tis_data priv;
0029 void __iomem *iobase;
0030 };
0031
0032 static inline struct tpm_tis_synquacer_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *data)
0033 {
0034 return container_of(data, struct tpm_tis_synquacer_phy, priv);
0035 }
0036
0037 static int tpm_tis_synquacer_read_bytes(struct tpm_tis_data *data, u32 addr,
0038 u16 len, u8 *result,
0039 enum tpm_tis_io_mode io_mode)
0040 {
0041 struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
0042 switch (io_mode) {
0043 case TPM_TIS_PHYS_8:
0044 while (len--)
0045 *result++ = ioread8(phy->iobase + addr);
0046 break;
0047 case TPM_TIS_PHYS_16:
0048 result[1] = ioread8(phy->iobase + addr + 1);
0049 result[0] = ioread8(phy->iobase + addr);
0050 break;
0051 case TPM_TIS_PHYS_32:
0052 result[3] = ioread8(phy->iobase + addr + 3);
0053 result[2] = ioread8(phy->iobase + addr + 2);
0054 result[1] = ioread8(phy->iobase + addr + 1);
0055 result[0] = ioread8(phy->iobase + addr);
0056 break;
0057 }
0058
0059 return 0;
0060 }
0061
0062 static int tpm_tis_synquacer_write_bytes(struct tpm_tis_data *data, u32 addr,
0063 u16 len, const u8 *value,
0064 enum tpm_tis_io_mode io_mode)
0065 {
0066 struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
0067 switch (io_mode) {
0068 case TPM_TIS_PHYS_8:
0069 while (len--)
0070 iowrite8(*value++, phy->iobase + addr);
0071 break;
0072 case TPM_TIS_PHYS_16:
0073 return -EINVAL;
0074 case TPM_TIS_PHYS_32:
0075
0076
0077
0078
0079 iowrite8(value[3], phy->iobase + addr + 3);
0080 iowrite8(value[2], phy->iobase + addr + 2);
0081 iowrite8(value[1], phy->iobase + addr + 1);
0082 iowrite8(value[0], phy->iobase + addr);
0083 break;
0084 }
0085
0086 return 0;
0087 }
0088
0089 static const struct tpm_tis_phy_ops tpm_tcg_bw = {
0090 .read_bytes = tpm_tis_synquacer_read_bytes,
0091 .write_bytes = tpm_tis_synquacer_write_bytes,
0092 };
0093
0094 static int tpm_tis_synquacer_init(struct device *dev,
0095 struct tpm_tis_synquacer_info *tpm_info)
0096 {
0097 struct tpm_tis_synquacer_phy *phy;
0098
0099 phy = devm_kzalloc(dev, sizeof(struct tpm_tis_synquacer_phy), GFP_KERNEL);
0100 if (phy == NULL)
0101 return -ENOMEM;
0102
0103 phy->iobase = devm_ioremap_resource(dev, &tpm_info->res);
0104 if (IS_ERR(phy->iobase))
0105 return PTR_ERR(phy->iobase);
0106
0107 return tpm_tis_core_init(dev, &phy->priv, tpm_info->irq, &tpm_tcg_bw,
0108 ACPI_HANDLE(dev));
0109 }
0110
0111 static SIMPLE_DEV_PM_OPS(tpm_tis_synquacer_pm, tpm_pm_suspend, tpm_tis_resume);
0112
0113 static int tpm_tis_synquacer_probe(struct platform_device *pdev)
0114 {
0115 struct tpm_tis_synquacer_info tpm_info = {};
0116 struct resource *res;
0117
0118 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0119 if (res == NULL) {
0120 dev_err(&pdev->dev, "no memory resource defined\n");
0121 return -ENODEV;
0122 }
0123 tpm_info.res = *res;
0124
0125 tpm_info.irq = -1;
0126
0127 return tpm_tis_synquacer_init(&pdev->dev, &tpm_info);
0128 }
0129
0130 static int tpm_tis_synquacer_remove(struct platform_device *pdev)
0131 {
0132 struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
0133
0134 tpm_chip_unregister(chip);
0135 tpm_tis_remove(chip);
0136
0137 return 0;
0138 }
0139
0140 #ifdef CONFIG_OF
0141 static const struct of_device_id tis_synquacer_of_platform_match[] = {
0142 {.compatible = "socionext,synquacer-tpm-mmio"},
0143 {},
0144 };
0145 MODULE_DEVICE_TABLE(of, tis_synquacer_of_platform_match);
0146 #endif
0147
0148 #ifdef CONFIG_ACPI
0149 static const struct acpi_device_id tpm_synquacer_acpi_tbl[] = {
0150 { "SCX0009" },
0151 {},
0152 };
0153 MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl);
0154 #endif
0155
0156 static struct platform_driver tis_synquacer_drv = {
0157 .probe = tpm_tis_synquacer_probe,
0158 .remove = tpm_tis_synquacer_remove,
0159 .driver = {
0160 .name = "tpm_tis_synquacer",
0161 .pm = &tpm_tis_synquacer_pm,
0162 .of_match_table = of_match_ptr(tis_synquacer_of_platform_match),
0163 .acpi_match_table = ACPI_PTR(tpm_synquacer_acpi_tbl),
0164 },
0165 };
0166
0167 static int __init tpm_tis_synquacer_module_init(void)
0168 {
0169 int rc;
0170
0171 rc = platform_driver_register(&tis_synquacer_drv);
0172 if (rc)
0173 return rc;
0174
0175 return 0;
0176 }
0177
0178 static void __exit tpm_tis_synquacer_module_exit(void)
0179 {
0180 platform_driver_unregister(&tis_synquacer_drv);
0181 }
0182
0183 module_init(tpm_tis_synquacer_module_init);
0184 module_exit(tpm_tis_synquacer_module_exit);
0185 MODULE_DESCRIPTION("TPM MMIO Driver for Socionext SynQuacer platform");
0186 MODULE_LICENSE("GPL");