1 // SPDX-License-Identifier: GPL-2.0
3 * Linux driver for RPC-IF HyperFlash
5 * Copyright (C) 2019-2020 Cogent Embedded, Inc.
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/mtd/hyperbus.h>
12 #include <linux/mtd/mtd.h>
13 #include <linux/mux/consumer.h>
15 #include <linux/platform_device.h>
16 #include <linux/types.h>
18 #include <memory/renesas-rpc-if.h>
20 struct rpcif_hyperbus
{
22 struct hyperbus_ctlr ctlr
;
23 struct hyperbus_device hbdev
;
26 static const struct rpcif_op rpcif_op_tmpl
= {
46 static void rpcif_hb_prepare_read(struct rpcif
*rpc
, void *to
,
47 unsigned long from
, ssize_t len
)
49 struct rpcif_op op
= rpcif_op_tmpl
;
51 op
.cmd
.opcode
= HYPERBUS_RW_READ
| HYPERBUS_AS_MEM
;
52 op
.addr
.val
= from
>> 1;
53 op
.dummy
.buswidth
= 1;
54 op
.dummy
.ncycles
= 15;
55 op
.data
.dir
= RPCIF_DATA_IN
;
59 rpcif_prepare(rpc
, &op
, NULL
, NULL
);
62 static void rpcif_hb_prepare_write(struct rpcif
*rpc
, unsigned long to
,
63 void *from
, ssize_t len
)
65 struct rpcif_op op
= rpcif_op_tmpl
;
67 op
.cmd
.opcode
= HYPERBUS_RW_WRITE
| HYPERBUS_AS_MEM
;
68 op
.addr
.val
= to
>> 1;
69 op
.data
.dir
= RPCIF_DATA_OUT
;
71 op
.data
.buf
.out
= from
;
73 rpcif_prepare(rpc
, &op
, NULL
, NULL
);
76 static u16
rpcif_hb_read16(struct hyperbus_device
*hbdev
, unsigned long addr
)
78 struct rpcif_hyperbus
*hyperbus
=
79 container_of(hbdev
, struct rpcif_hyperbus
, hbdev
);
82 rpcif_hb_prepare_read(&hyperbus
->rpc
, &data
, addr
, 2);
84 rpcif_manual_xfer(&hyperbus
->rpc
);
89 static void rpcif_hb_write16(struct hyperbus_device
*hbdev
, unsigned long addr
,
92 struct rpcif_hyperbus
*hyperbus
=
93 container_of(hbdev
, struct rpcif_hyperbus
, hbdev
);
95 rpcif_hb_prepare_write(&hyperbus
->rpc
, addr
, &data
, 2);
97 rpcif_manual_xfer(&hyperbus
->rpc
);
100 static void rpcif_hb_copy_from(struct hyperbus_device
*hbdev
, void *to
,
101 unsigned long from
, ssize_t len
)
103 struct rpcif_hyperbus
*hyperbus
=
104 container_of(hbdev
, struct rpcif_hyperbus
, hbdev
);
106 rpcif_hb_prepare_read(&hyperbus
->rpc
, to
, from
, len
);
108 rpcif_dirmap_read(&hyperbus
->rpc
, from
, len
, to
);
111 static const struct hyperbus_ops rpcif_hb_ops
= {
112 .read16
= rpcif_hb_read16
,
113 .write16
= rpcif_hb_write16
,
114 .copy_from
= rpcif_hb_copy_from
,
117 static int rpcif_hb_probe(struct platform_device
*pdev
)
119 struct device
*dev
= &pdev
->dev
;
120 struct rpcif_hyperbus
*hyperbus
;
123 hyperbus
= devm_kzalloc(dev
, sizeof(*hyperbus
), GFP_KERNEL
);
127 rpcif_sw_init(&hyperbus
->rpc
, pdev
->dev
.parent
);
129 platform_set_drvdata(pdev
, hyperbus
);
131 rpcif_enable_rpm(&hyperbus
->rpc
);
133 rpcif_hw_init(&hyperbus
->rpc
, true);
135 hyperbus
->hbdev
.map
.size
= hyperbus
->rpc
.size
;
136 hyperbus
->hbdev
.map
.virt
= hyperbus
->rpc
.dirmap
;
138 hyperbus
->ctlr
.dev
= dev
;
139 hyperbus
->ctlr
.ops
= &rpcif_hb_ops
;
140 hyperbus
->hbdev
.ctlr
= &hyperbus
->ctlr
;
141 hyperbus
->hbdev
.np
= of_get_next_child(pdev
->dev
.parent
->of_node
, NULL
);
142 error
= hyperbus_register_device(&hyperbus
->hbdev
);
144 rpcif_disable_rpm(&hyperbus
->rpc
);
149 static int rpcif_hb_remove(struct platform_device
*pdev
)
151 struct rpcif_hyperbus
*hyperbus
= platform_get_drvdata(pdev
);
152 int error
= hyperbus_unregister_device(&hyperbus
->hbdev
);
153 struct rpcif
*rpc
= dev_get_drvdata(pdev
->dev
.parent
);
155 rpcif_disable_rpm(rpc
);
159 static struct platform_driver rpcif_platform_driver
= {
160 .probe
= rpcif_hb_probe
,
161 .remove
= rpcif_hb_remove
,
163 .name
= "rpc-if-hyperflash",
167 module_platform_driver(rpcif_platform_driver
);
169 MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
170 MODULE_LICENSE("GPL v2");