1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (C) 2019 Texas Instruments Incorporated - http://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/of_address.h>
14 #include <linux/types.h>
16 static struct hyperbus_device
*map_to_hbdev(struct map_info
*map
)
18 return container_of(map
, struct hyperbus_device
, map
);
21 static map_word
hyperbus_read16(struct map_info
*map
, unsigned long addr
)
23 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
24 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
27 read_data
.x
[0] = ctlr
->ops
->read16(hbdev
, addr
);
32 static void hyperbus_write16(struct map_info
*map
, map_word d
,
35 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
36 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
38 ctlr
->ops
->write16(hbdev
, addr
, d
.x
[0]);
41 static void hyperbus_copy_from(struct map_info
*map
, void *to
,
42 unsigned long from
, ssize_t len
)
44 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
45 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
47 ctlr
->ops
->copy_from(hbdev
, to
, from
, len
);
50 static void hyperbus_copy_to(struct map_info
*map
, unsigned long to
,
51 const void *from
, ssize_t len
)
53 struct hyperbus_device
*hbdev
= map_to_hbdev(map
);
54 struct hyperbus_ctlr
*ctlr
= hbdev
->ctlr
;
56 ctlr
->ops
->copy_to(hbdev
, to
, from
, len
);
59 int hyperbus_register_device(struct hyperbus_device
*hbdev
)
61 const struct hyperbus_ops
*ops
;
62 struct hyperbus_ctlr
*ctlr
;
63 struct device_node
*np
;
69 if (!hbdev
|| !hbdev
->np
|| !hbdev
->ctlr
|| !hbdev
->ctlr
->dev
) {
70 pr_err("hyperbus: please fill all the necessary fields!\n");
76 if (!of_device_is_compatible(np
, "cypress,hyperflash"))
79 hbdev
->memtype
= HYPERFLASH
;
81 ret
= of_address_to_resource(np
, 0, &res
);
87 map
->size
= resource_size(&res
);
88 map
->virt
= devm_ioremap_resource(dev
, &res
);
89 if (IS_ERR(map
->virt
))
90 return PTR_ERR(map
->virt
);
92 map
->name
= dev_name(dev
);
94 map
->device_node
= np
;
100 map
->read
= hyperbus_read16
;
102 map
->write
= hyperbus_write16
;
104 map
->copy_to
= hyperbus_copy_to
;
106 map
->copy_from
= hyperbus_copy_from
;
108 if (ops
->calibrate
&& !ctlr
->calibrated
) {
109 ret
= ops
->calibrate(hbdev
);
111 dev_err(dev
, "Calibration failed\n");
114 ctlr
->calibrated
= true;
118 hbdev
->mtd
= do_map_probe("cfi_probe", map
);
120 dev_err(dev
, "probing of hyperbus device failed\n");
124 hbdev
->mtd
->dev
.parent
= dev
;
125 mtd_set_of_node(hbdev
->mtd
, np
);
127 ret
= mtd_device_register(hbdev
->mtd
, NULL
, 0);
129 dev_err(dev
, "failed to register mtd device\n");
130 map_destroy(hbdev
->mtd
);
136 EXPORT_SYMBOL_GPL(hyperbus_register_device
);
138 int hyperbus_unregister_device(struct hyperbus_device
*hbdev
)
142 if (hbdev
&& hbdev
->mtd
) {
143 ret
= mtd_device_unregister(hbdev
->mtd
);
144 map_destroy(hbdev
->mtd
);
149 EXPORT_SYMBOL_GPL(hyperbus_unregister_device
);
151 MODULE_DESCRIPTION("HyperBus Framework");
152 MODULE_LICENSE("GPL v2");
153 MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");