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/cfi.h>
10 #include <linux/mtd/hyperbus.h>
11 #include <linux/mtd/mtd.h>
12 #include <linux/mux/consumer.h>
14 #include <linux/of_address.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/types.h>
19 #define AM654_HBMC_CALIB_COUNT 25
21 struct am654_hbmc_priv
{
22 struct hyperbus_ctlr ctlr
;
23 struct hyperbus_device hbdev
;
24 struct mux_control
*mux_ctrl
;
27 static int am654_hbmc_calibrate(struct hyperbus_device
*hbdev
)
29 struct map_info
*map
= &hbdev
->map
;
30 struct cfi_private cfi
;
31 int count
= AM654_HBMC_CALIB_COUNT
;
36 cfi
.device_type
= CFI_DEVICETYPE_X16
;
37 cfi_send_gen_cmd(0xF0, 0, 0, map
, &cfi
, cfi
.device_type
, NULL
);
38 cfi_send_gen_cmd(0x98, 0x55, 0, map
, &cfi
, cfi
.device_type
, NULL
);
41 ret
= cfi_qry_present(map
, 0, &cfi
);
50 cfi_qry_mode_off(0, map
, &cfi
);
55 static const struct hyperbus_ops am654_hbmc_ops
= {
56 .calibrate
= am654_hbmc_calibrate
,
59 static int am654_hbmc_probe(struct platform_device
*pdev
)
61 struct device_node
*np
= pdev
->dev
.of_node
;
62 struct device
*dev
= &pdev
->dev
;
63 struct am654_hbmc_priv
*priv
;
67 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
71 platform_set_drvdata(pdev
, priv
);
73 ret
= of_address_to_resource(np
, 0, &res
);
77 if (of_property_read_bool(dev
->of_node
, "mux-controls")) {
78 struct mux_control
*control
= devm_mux_control_get(dev
, NULL
);
81 return PTR_ERR(control
);
83 ret
= mux_control_select(control
, 1);
85 dev_err(dev
, "Failed to select HBMC mux\n");
88 priv
->mux_ctrl
= control
;
91 pm_runtime_enable(dev
);
92 ret
= pm_runtime_get_sync(dev
);
94 pm_runtime_put_noidle(dev
);
98 priv
->hbdev
.map
.size
= resource_size(&res
);
99 priv
->hbdev
.map
.virt
= devm_ioremap_resource(dev
, &res
);
100 if (IS_ERR(priv
->hbdev
.map
.virt
))
101 return PTR_ERR(priv
->hbdev
.map
.virt
);
103 priv
->ctlr
.dev
= dev
;
104 priv
->ctlr
.ops
= &am654_hbmc_ops
;
105 priv
->hbdev
.ctlr
= &priv
->ctlr
;
106 priv
->hbdev
.np
= of_get_next_child(dev
->of_node
, NULL
);
107 ret
= hyperbus_register_device(&priv
->hbdev
);
109 dev_err(dev
, "failed to register controller\n");
110 pm_runtime_put_sync(&pdev
->dev
);
116 pm_runtime_disable(dev
);
118 mux_control_deselect(priv
->mux_ctrl
);
122 static int am654_hbmc_remove(struct platform_device
*pdev
)
124 struct am654_hbmc_priv
*priv
= platform_get_drvdata(pdev
);
127 ret
= hyperbus_unregister_device(&priv
->hbdev
);
129 mux_control_deselect(priv
->mux_ctrl
);
130 pm_runtime_put_sync(&pdev
->dev
);
131 pm_runtime_disable(&pdev
->dev
);
136 static const struct of_device_id am654_hbmc_dt_ids
[] = {
138 .compatible
= "ti,am654-hbmc",
140 { /* end of table */ }
143 MODULE_DEVICE_TABLE(of
, am654_hbmc_dt_ids
);
145 static struct platform_driver am654_hbmc_platform_driver
= {
146 .probe
= am654_hbmc_probe
,
147 .remove
= am654_hbmc_remove
,
149 .name
= "hbmc-am654",
150 .of_match_table
= am654_hbmc_dt_ids
,
154 module_platform_driver(am654_hbmc_platform_driver
);
156 MODULE_DESCRIPTION("HBMC driver for AM654 SoC");
157 MODULE_LICENSE("GPL v2");
158 MODULE_ALIAS("platform:hbmc-am654");
159 MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");