223 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/iopoll.h>4#include <linux/module.h>5#include <linux/nvmem-provider.h>6#include <linux/of.h>7#include <linux/platform_device.h>8 9#define OTP_OTP_PWR_DN(t) (t + 0x00)10#define OTP_OTP_PWR_DN_OTP_PWRDN_N BIT(0)11#define OTP_OTP_ADDR_HI(t) (t + 0x04)12#define OTP_OTP_ADDR_LO(t) (t + 0x08)13#define OTP_OTP_PRGM_DATA(t) (t + 0x10)14#define OTP_OTP_PRGM_MODE(t) (t + 0x14)15#define OTP_OTP_PRGM_MODE_OTP_PGM_MODE_BYTE BIT(0)16#define OTP_OTP_RD_DATA(t) (t + 0x18)17#define OTP_OTP_FUNC_CMD(t) (t + 0x20)18#define OTP_OTP_FUNC_CMD_OTP_PROGRAM BIT(1)19#define OTP_OTP_FUNC_CMD_OTP_READ BIT(0)20#define OTP_OTP_CMD_GO(t) (t + 0x28)21#define OTP_OTP_CMD_GO_OTP_GO BIT(0)22#define OTP_OTP_PASS_FAIL(t) (t + 0x2c)23#define OTP_OTP_PASS_FAIL_OTP_READ_PROHIBITED BIT(3)24#define OTP_OTP_PASS_FAIL_OTP_WRITE_PROHIBITED BIT(2)25#define OTP_OTP_PASS_FAIL_OTP_FAIL BIT(0)26#define OTP_OTP_STATUS(t) (t + 0x30)27#define OTP_OTP_STATUS_OTP_CPUMPEN BIT(1)28#define OTP_OTP_STATUS_OTP_BUSY BIT(0)29 30#define OTP_MEM_SIZE 819231#define OTP_SLEEP_US 1032#define OTP_TIMEOUT_US 50000033 34struct lan9662_otp {35 struct device *dev;36 void __iomem *base;37};38 39static int lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag)40{41 u32 val;42 43 return readl_poll_timeout(reg, val, !(val & flag),44 OTP_SLEEP_US, OTP_TIMEOUT_US);45}46 47static int lan9662_otp_power(struct lan9662_otp *otp, bool up)48{49 void __iomem *pwrdn = OTP_OTP_PWR_DN(otp->base);50 51 if (up) {52 writel(readl(pwrdn) & ~OTP_OTP_PWR_DN_OTP_PWRDN_N, pwrdn);53 if (lan9662_otp_wait_flag_clear(OTP_OTP_STATUS(otp->base),54 OTP_OTP_STATUS_OTP_CPUMPEN))55 return -ETIMEDOUT;56 } else {57 writel(readl(pwrdn) | OTP_OTP_PWR_DN_OTP_PWRDN_N, pwrdn);58 }59 60 return 0;61}62 63static int lan9662_otp_execute(struct lan9662_otp *otp)64{65 if (lan9662_otp_wait_flag_clear(OTP_OTP_CMD_GO(otp->base),66 OTP_OTP_CMD_GO_OTP_GO))67 return -ETIMEDOUT;68 69 if (lan9662_otp_wait_flag_clear(OTP_OTP_STATUS(otp->base),70 OTP_OTP_STATUS_OTP_BUSY))71 return -ETIMEDOUT;72 73 return 0;74}75 76static void lan9662_otp_set_address(struct lan9662_otp *otp, u32 offset)77{78 writel(0xff & (offset >> 8), OTP_OTP_ADDR_HI(otp->base));79 writel(0xff & offset, OTP_OTP_ADDR_LO(otp->base));80}81 82static int lan9662_otp_read_byte(struct lan9662_otp *otp, u32 offset, u8 *dst)83{84 u32 pass;85 int rc;86 87 lan9662_otp_set_address(otp, offset);88 writel(OTP_OTP_FUNC_CMD_OTP_READ, OTP_OTP_FUNC_CMD(otp->base));89 writel(OTP_OTP_CMD_GO_OTP_GO, OTP_OTP_CMD_GO(otp->base));90 rc = lan9662_otp_execute(otp);91 if (!rc) {92 pass = readl(OTP_OTP_PASS_FAIL(otp->base));93 if (pass & OTP_OTP_PASS_FAIL_OTP_READ_PROHIBITED)94 return -EACCES;95 *dst = (u8) readl(OTP_OTP_RD_DATA(otp->base));96 }97 return rc;98}99 100static int lan9662_otp_write_byte(struct lan9662_otp *otp, u32 offset, u8 data)101{102 u32 pass;103 int rc;104 105 lan9662_otp_set_address(otp, offset);106 writel(OTP_OTP_PRGM_MODE_OTP_PGM_MODE_BYTE, OTP_OTP_PRGM_MODE(otp->base));107 writel(data, OTP_OTP_PRGM_DATA(otp->base));108 writel(OTP_OTP_FUNC_CMD_OTP_PROGRAM, OTP_OTP_FUNC_CMD(otp->base));109 writel(OTP_OTP_CMD_GO_OTP_GO, OTP_OTP_CMD_GO(otp->base));110 111 rc = lan9662_otp_execute(otp);112 if (!rc) {113 pass = readl(OTP_OTP_PASS_FAIL(otp->base));114 if (pass & OTP_OTP_PASS_FAIL_OTP_WRITE_PROHIBITED)115 return -EACCES;116 if (pass & OTP_OTP_PASS_FAIL_OTP_FAIL)117 return -EIO;118 }119 return rc;120}121 122static int lan9662_otp_read(void *context, unsigned int offset,123 void *_val, size_t bytes)124{125 struct lan9662_otp *otp = context;126 u8 *val = _val;127 uint8_t data;128 int i, rc = 0;129 130 lan9662_otp_power(otp, true);131 for (i = 0; i < bytes; i++) {132 rc = lan9662_otp_read_byte(otp, offset + i, &data);133 if (rc < 0)134 break;135 *val++ = data;136 }137 lan9662_otp_power(otp, false);138 139 return rc;140}141 142static int lan9662_otp_write(void *context, unsigned int offset,143 void *_val, size_t bytes)144{145 struct lan9662_otp *otp = context;146 u8 *val = _val;147 u8 data, newdata;148 int i, rc = 0;149 150 lan9662_otp_power(otp, true);151 for (i = 0; i < bytes; i++) {152 /* Skip zero bytes */153 if (val[i]) {154 rc = lan9662_otp_read_byte(otp, offset + i, &data);155 if (rc < 0)156 break;157 158 newdata = data | val[i];159 if (newdata == data)160 continue;161 162 rc = lan9662_otp_write_byte(otp, offset + i,163 newdata);164 if (rc < 0)165 break;166 }167 }168 lan9662_otp_power(otp, false);169 170 return rc;171}172 173static struct nvmem_config otp_config = {174 .name = "lan9662-otp",175 .stride = 1,176 .word_size = 1,177 .reg_read = lan9662_otp_read,178 .reg_write = lan9662_otp_write,179 .size = OTP_MEM_SIZE,180};181 182static int lan9662_otp_probe(struct platform_device *pdev)183{184 struct device *dev = &pdev->dev;185 struct nvmem_device *nvmem;186 struct lan9662_otp *otp;187 188 otp = devm_kzalloc(&pdev->dev, sizeof(*otp), GFP_KERNEL);189 if (!otp)190 return -ENOMEM;191 192 otp->dev = dev;193 otp->base = devm_platform_ioremap_resource(pdev, 0);194 if (IS_ERR(otp->base))195 return PTR_ERR(otp->base);196 197 otp_config.priv = otp;198 otp_config.dev = dev;199 200 nvmem = devm_nvmem_register(dev, &otp_config);201 202 return PTR_ERR_OR_ZERO(nvmem);203}204 205static const struct of_device_id lan9662_otp_match[] = {206 { .compatible = "microchip,lan9662-otpc", },207 { },208};209MODULE_DEVICE_TABLE(of, lan9662_otp_match);210 211static struct platform_driver lan9662_otp_driver = {212 .probe = lan9662_otp_probe,213 .driver = {214 .name = "lan9662-otp",215 .of_match_table = lan9662_otp_match,216 },217};218module_platform_driver(lan9662_otp_driver);219 220MODULE_AUTHOR("Horatiu Vultur <horatiu.vultur@microchip.com>");221MODULE_DESCRIPTION("lan9662 OTP driver");222MODULE_LICENSE("GPL");223