VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   33 Branches   55 Tags
c942fddf8793b (Thomas Gleixner     2019-05-27 08:55:06 +0200   1) // SPDX-License-Identifier: GPL-2.0-or-later
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   2) /*
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   3)  * Freescale MXS On-Chip OTP driver
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   4)  *
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   5)  * Copyright (C) 2015 Stefan Wahren <stefan.wahren@i2se.com>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   6)  *
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   7)  * Based on the driver from Huang Shijie and Christoph G. Baumann
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   8)  */
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100   9) #include <linux/clk.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  10) #include <linux/delay.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  11) #include <linux/device.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  12) #include <linux/err.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  13) #include <linux/io.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  14) #include <linux/module.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  15) #include <linux/nvmem-provider.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  16) #include <linux/of_device.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  17) #include <linux/platform_device.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  18) #include <linux/slab.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  19) #include <linux/stmp_device.h>
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  20) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  21) /* OCOTP registers and bits */
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  22) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  23) #define BM_OCOTP_CTRL_RD_BANK_OPEN	BIT(12)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  24) #define BM_OCOTP_CTRL_ERROR		BIT(9)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  25) #define BM_OCOTP_CTRL_BUSY		BIT(8)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  26) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  27) #define OCOTP_TIMEOUT		10000
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  28) #define OCOTP_DATA_OFFSET	0x20
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  29) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  30) struct mxs_ocotp {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  31) 	struct clk *clk;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  32) 	void __iomem *base;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  33) 	struct nvmem_device *nvmem;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  34) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  35) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  36) static int mxs_ocotp_wait(struct mxs_ocotp *otp)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  37) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  38) 	int timeout = OCOTP_TIMEOUT;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  39) 	unsigned int status = 0;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  40) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  41) 	while (timeout--) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  42) 		status = readl(otp->base);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  43) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  44) 		if (!(status & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR)))
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  45) 			break;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  46) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  47) 		cpu_relax();
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  48) 	}
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  49) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  50) 	if (status & BM_OCOTP_CTRL_BUSY)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  51) 		return -EBUSY;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  52) 	else if (status & BM_OCOTP_CTRL_ERROR)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  53) 		return -EIO;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  54) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  55) 	return 0;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  56) }
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  57) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  58) static int mxs_ocotp_read(void *context, unsigned int offset,
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  59) 			  void *val, size_t bytes)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  60) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  61) 	struct mxs_ocotp *otp = context;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  62) 	u32 *buf = val;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  63) 	int ret;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  64) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  65) 	ret = clk_enable(otp->clk);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  66) 	if (ret)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  67) 		return ret;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  68) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  69) 	writel(BM_OCOTP_CTRL_ERROR, otp->base + STMP_OFFSET_REG_CLR);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  70) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  71) 	ret = mxs_ocotp_wait(otp);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  72) 	if (ret)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  73) 		goto disable_clk;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  74) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  75) 	/* open OCOTP banks for read */
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  76) 	writel(BM_OCOTP_CTRL_RD_BANK_OPEN, otp->base + STMP_OFFSET_REG_SET);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  77) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  78) 	/* approximately wait 33 hclk cycles */
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  79) 	udelay(1);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  80) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  81) 	ret = mxs_ocotp_wait(otp);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  82) 	if (ret)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  83) 		goto close_banks;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  84) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  85) 	while (bytes) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  86) 		if ((offset < OCOTP_DATA_OFFSET) || (offset % 16)) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  87) 			/* fill up non-data register */
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  88) 			*buf++ = 0;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  89) 		} else {
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  90) 			*buf++ = readl(otp->base + offset);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  91) 		}
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  92) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  93) 		bytes -= 4;
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100  94) 		offset += 4;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  95) 	}
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  96) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  97) close_banks:
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  98) 	/* close banks for power saving */
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100  99) 	writel(BM_OCOTP_CTRL_RD_BANK_OPEN, otp->base + STMP_OFFSET_REG_CLR);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 100) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 101) disable_clk:
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 102) 	clk_disable(otp->clk);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 103) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 104) 	return ret;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 105) }
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 106) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 107) static struct nvmem_config ocotp_config = {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 108) 	.name = "mxs-ocotp",
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 109) 	.stride = 16,
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 110) 	.word_size = 4,
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 111) 	.reg_read = mxs_ocotp_read,
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 112) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 113) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 114) struct mxs_data {
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 115) 	int size;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 116) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 117) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 118) static const struct mxs_data imx23_data = {
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 119) 	.size = 0x220,
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 120) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 121) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 122) static const struct mxs_data imx28_data = {
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 123) 	.size = 0x2a0,
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 124) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 125) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 126) static const struct of_device_id mxs_ocotp_match[] = {
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 127) 	{ .compatible = "fsl,imx23-ocotp", .data = &imx23_data },
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 128) 	{ .compatible = "fsl,imx28-ocotp", .data = &imx28_data },
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 129) 	{ /* sentinel */},
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 130) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 131) MODULE_DEVICE_TABLE(of, mxs_ocotp_match);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 132) 
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 133) static void mxs_ocotp_action(void *data)
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 134) {
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 135) 	clk_unprepare(data);
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 136) }
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 137) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 138) static int mxs_ocotp_probe(struct platform_device *pdev)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 139) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 140) 	struct device *dev = &pdev->dev;
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 141) 	const struct mxs_data *data;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 142) 	struct mxs_ocotp *otp;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 143) 	const struct of_device_id *match;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 144) 	int ret;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 145) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 146) 	match = of_match_device(dev->driver->of_match_table, dev);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 147) 	if (!match || !match->data)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 148) 		return -EINVAL;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 149) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 150) 	otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 151) 	if (!otp)
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 152) 		return -ENOMEM;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 153) 
794a1e229b92a (Anson Huang         2019-04-13 11:33:00 +0100 154) 	otp->base = devm_platform_ioremap_resource(pdev, 0);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 155) 	if (IS_ERR(otp->base))
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 156) 		return PTR_ERR(otp->base);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 157) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 158) 	otp->clk = devm_clk_get(&pdev->dev, NULL);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 159) 	if (IS_ERR(otp->clk))
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 160) 		return PTR_ERR(otp->clk);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 161) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 162) 	ret = clk_prepare(otp->clk);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 163) 	if (ret < 0) {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 164) 		dev_err(dev, "failed to prepare clk: %d\n", ret);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 165) 		return ret;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 166) 	}
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 167) 
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 168) 	ret = devm_add_action_or_reset(&pdev->dev, mxs_ocotp_action, otp->clk);
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 169) 	if (ret)
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 170) 		return ret;
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 171) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 172) 	data = match->data;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 173) 
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 174) 	ocotp_config.size = data->size;
7d8867d71fba7 (Srinivas Kandagatla 2016-05-02 19:36:14 +0100 175) 	ocotp_config.priv = otp;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 176) 	ocotp_config.dev = dev;
7d9f9f24fac77 (Bartosz Golaszewski 2018-09-21 06:40:12 -0700 177) 	otp->nvmem = devm_nvmem_register(dev, &ocotp_config);
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 178) 	if (IS_ERR(otp->nvmem))
bbde5709ee4f6 (Anson Huang         2020-03-23 15:00:06 +0000 179) 		return PTR_ERR(otp->nvmem);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 180) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 181) 	platform_set_drvdata(pdev, otp);
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 182) 
7d9f9f24fac77 (Bartosz Golaszewski 2018-09-21 06:40:12 -0700 183) 	return 0;
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 184) }
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 185) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 186) static struct platform_driver mxs_ocotp_driver = {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 187) 	.probe = mxs_ocotp_probe,
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 188) 	.driver = {
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 189) 		.name = "mxs-ocotp",
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 190) 		.of_match_table = mxs_ocotp_match,
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 191) 	},
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 192) };
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 193) 
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 194) module_platform_driver(mxs_ocotp_driver);
5fb812293ad67 (Stefan Wahren       2019-08-18 10:33:43 +0100 195) MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net");
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 196) MODULE_DESCRIPTION("driver for OCOTP in i.MX23/i.MX28");
c01e9a11ab6f3 (Stefan Wahren       2015-09-30 13:56:27 +0100 197) MODULE_LICENSE("GPL v2");