1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2022 Rafał Miłecki <rafal@milecki.pl>
6 #include <linux/mod_devicetable.h>
7 #include <linux/module.h>
8 #include <linux/mtd/mtd.h>
9 #include <linux/nvmem-provider.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
14 #include "layouts/u-boot-env.h"
18 struct nvmem_device
*nvmem
;
19 enum u_boot_env_format format
;
24 static int u_boot_env_read(void *context
, unsigned int offset
, void *val
,
27 struct u_boot_env
*priv
= context
;
28 struct device
*dev
= priv
->dev
;
32 err
= mtd_read(priv
->mtd
, offset
, bytes
, &bytes_read
, val
);
33 if (err
&& !mtd_is_bitflip(err
)) {
34 dev_err(dev
, "Failed to read from mtd: %d\n", err
);
38 if (bytes_read
!= bytes
) {
39 dev_err(dev
, "Failed to read %zu bytes\n", bytes
);
46 static int u_boot_env_probe(struct platform_device
*pdev
)
48 struct nvmem_config config
= {
50 .reg_read
= u_boot_env_read
,
52 struct device
*dev
= &pdev
->dev
;
53 struct device_node
*np
= dev
->of_node
;
54 struct u_boot_env
*priv
;
56 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
61 priv
->format
= (uintptr_t)of_device_get_match_data(dev
);
63 priv
->mtd
= of_get_mtd_device_by_node(np
);
64 if (IS_ERR(priv
->mtd
)) {
65 dev_err_probe(dev
, PTR_ERR(priv
->mtd
), "Failed to get %pOF MTD\n", np
);
66 return PTR_ERR(priv
->mtd
);
71 config
.size
= priv
->mtd
->size
;
73 priv
->nvmem
= devm_nvmem_register(dev
, &config
);
74 if (IS_ERR(priv
->nvmem
))
75 return PTR_ERR(priv
->nvmem
);
77 return u_boot_env_parse(dev
, priv
->nvmem
, priv
->format
);
80 static const struct of_device_id u_boot_env_of_match_table
[] = {
81 { .compatible
= "u-boot,env", .data
= (void *)U_BOOT_FORMAT_SINGLE
, },
82 { .compatible
= "u-boot,env-redundant-bool", .data
= (void *)U_BOOT_FORMAT_REDUNDANT
, },
83 { .compatible
= "u-boot,env-redundant-count", .data
= (void *)U_BOOT_FORMAT_REDUNDANT
, },
84 { .compatible
= "brcm,env", .data
= (void *)U_BOOT_FORMAT_BROADCOM
, },
88 static struct platform_driver u_boot_env_driver
= {
89 .probe
= u_boot_env_probe
,
92 .of_match_table
= u_boot_env_of_match_table
,
95 module_platform_driver(u_boot_env_driver
);
97 MODULE_AUTHOR("Rafał Miłecki");
98 MODULE_DESCRIPTION("U-Boot environment variables support module");
99 MODULE_LICENSE("GPL");
100 MODULE_DEVICE_TABLE(of
, u_boot_env_of_match_table
);