1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Layerscape SFP driver 4 * 5 * Copyright (c) 2022 Michael Walle <michael@walle.cc> 6 * 7 */ 8 9 #include <linux/device.h> 10 #include <linux/io.h> 11 #include <linux/module.h> 12 #include <linux/nvmem-provider.h> 13 #include <linux/platform_device.h> 14 #include <linux/property.h> 15 #include <linux/regmap.h> 16 17 #define LAYERSCAPE_SFP_OTP_OFFSET 0x0200 18 19 struct layerscape_sfp_priv { 20 struct regmap *regmap; 21 }; 22 23 struct layerscape_sfp_data { 24 int size; 25 enum regmap_endian endian; 26 }; 27 28 static int layerscape_sfp_read(void *context, unsigned int offset, void *val, 29 size_t bytes) 30 { 31 struct layerscape_sfp_priv *priv = context; 32 33 return regmap_bulk_read(priv->regmap, 34 LAYERSCAPE_SFP_OTP_OFFSET + offset, val, 35 bytes / 4); 36 } 37 38 static struct nvmem_config layerscape_sfp_nvmem_config = { 39 .name = "fsl-sfp", 40 .reg_read = layerscape_sfp_read, 41 .word_size = 4, 42 .stride = 4, 43 }; 44 45 static int layerscape_sfp_probe(struct platform_device *pdev) 46 { 47 const struct layerscape_sfp_data *data; 48 struct layerscape_sfp_priv *priv; 49 struct nvmem_device *nvmem; 50 struct regmap_config config = { 0 }; 51 void __iomem *base; 52 53 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 54 if (!priv) 55 return -ENOMEM; 56 57 base = devm_platform_ioremap_resource(pdev, 0); 58 if (IS_ERR(base)) 59 return PTR_ERR(base); 60 61 data = device_get_match_data(&pdev->dev); 62 config.reg_bits = 32; 63 config.reg_stride = 4; 64 config.val_bits = 32; 65 config.val_format_endian = data->endian; 66 config.max_register = LAYERSCAPE_SFP_OTP_OFFSET + data->size - 4; 67 priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, &config); 68 if (IS_ERR(priv->regmap)) 69 return PTR_ERR(priv->regmap); 70 71 layerscape_sfp_nvmem_config.size = data->size; 72 layerscape_sfp_nvmem_config.dev = &pdev->dev; 73 layerscape_sfp_nvmem_config.priv = priv; 74 75 nvmem = devm_nvmem_register(&pdev->dev, &layerscape_sfp_nvmem_config); 76 77 return PTR_ERR_OR_ZERO(nvmem); 78 } 79 80 static const struct layerscape_sfp_data ls1021a_data = { 81 .size = 0x88, 82 .endian = REGMAP_ENDIAN_BIG, 83 }; 84 85 static const struct layerscape_sfp_data ls1028a_data = { 86 .size = 0x88, 87 .endian = REGMAP_ENDIAN_LITTLE, 88 }; 89 90 static const struct of_device_id layerscape_sfp_dt_ids[] = { 91 { .compatible = "fsl,ls1021a-sfp", .data = &ls1021a_data }, 92 { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data }, 93 {}, 94 }; 95 MODULE_DEVICE_TABLE(of, layerscape_sfp_dt_ids); 96 97 static struct platform_driver layerscape_sfp_driver = { 98 .probe = layerscape_sfp_probe, 99 .driver = { 100 .name = "layerscape_sfp", 101 .of_match_table = layerscape_sfp_dt_ids, 102 }, 103 }; 104 module_platform_driver(layerscape_sfp_driver); 105 106 MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); 107 MODULE_DESCRIPTION("Layerscape Security Fuse Processor driver"); 108 MODULE_LICENSE("GPL"); 109