1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
4 // Author: Vignesh Raghavendra <vigneshr@ti.com>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/mtd/hyperbus.h>
10 #include <linux/mtd/map.h>
11 #include <linux/mtd/mtd.h>
13 #include <linux/types.h>
15 static struct hyperbus_device
*map_to_hbdev(struct map_info
*map
)
17 return container_of(map
, struct hyperbus_device
, map
);
20 static map_word
hyperbus_read16(struct map_info
*map
, unsigned long addr
)
22 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
23 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
26 read_data
.x
[0] = ctlr
->ops
->read16(hbdev
, addr
);
31 static void hyperbus_write16(struct map_info
*map
, map_word d
,
34 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
35 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
37 ctlr
->ops
->write16(hbdev
, addr
, d
.x
[0]);
40 static void hyperbus_copy_from(struct map_info
*map
, void *to
,
41 unsigned long from
, ssize_t len
)
43 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
44 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
46 ctlr
->ops
->copy_from(hbdev
, to
, from
, len
);
49 static void hyperbus_copy_to(struct map_info
*map
, unsigned long to
,
50 const void *from
, ssize_t len
)
52 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
53 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
55 ctlr
->ops
->copy_to(hbdev
, to
, from
, len
);
58 int hyperbus_register_device(struct hyperbus_device
*hbdev
)
60 const struct hyperbus_ops
*ops
;
61 struct hyperbus_ctlr
*ctlr
;
62 struct device_node
*np
;
67 if (!hbdev
|| !hbdev
->np
|| !hbdev
->ctlr
|| !hbdev
->ctlr
->dev
) {
68 pr_err("hyperbus: please fill all the necessary fields!\n");
74 if (!of_device_is_compatible(np
, "cypress,hyperflash")) {
75 dev_err(ctlr
->dev
, "\"cypress,hyperflash\" compatible missing\n");
79 hbdev
->memtype
= HYPERFLASH
;
83 map
->name
= dev_name(dev
);
85 map
->device_node
= np
;
91 map
->read
= hyperbus_read16
;
93 map
->write
= hyperbus_write16
;
95 map
->copy_to
= hyperbus_copy_to
;
97 map
->copy_from
= hyperbus_copy_from
;
99 if (ops
->calibrate
&& !ctlr
->calibrated
) {
100 ret
= ops
->calibrate(hbdev
);
102 dev_err(dev
, "Calibration failed\n");
105 ctlr
->calibrated
= true;
109 hbdev
->mtd
= do_map_probe("cfi_probe", map
);
111 dev_err(dev
, "probing of hyperbus device failed\n");
115 hbdev
->mtd
->dev
.parent
= dev
;
116 mtd_set_of_node(hbdev
->mtd
, np
);
118 ret
= mtd_device_register(hbdev
->mtd
, NULL
, 0);
120 dev_err(dev
, "failed to register mtd device\n");
121 map_destroy(hbdev
->mtd
);
127 EXPORT_SYMBOL_GPL(hyperbus_register_device
);
129 int hyperbus_unregister_device(struct hyperbus_device
*hbdev
)
133 if (hbdev
&& hbdev
->mtd
) {
134 ret
= mtd_device_unregister(hbdev
->mtd
);
135 map_destroy(hbdev
->mtd
);
140 EXPORT_SYMBOL_GPL(hyperbus_unregister_device
);
142 MODULE_DESCRIPTION("HyperBus Framework");
143 MODULE_LICENSE("GPL v2");
144 MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");