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