1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2017-2026 Morse Micro
4 */
5 #include <linux/module.h>
6 #include "core.h"
7 #include "bus.h"
8 #include "hif.h"
9 #include "mac.h"
10
mm81x_core_attach_regs(struct mm81x * mors)11 static int mm81x_core_attach_regs(struct mm81x *mors)
12 {
13 int ret = 0;
14
15 mm81x_claim_bus(mors);
16 ret = mm81x_reg32_read(mors, MM8108_REG_CHIP_ID, &mors->chip_id);
17 mm81x_release_bus(mors);
18
19 if (ret < 0) {
20 dev_err(mors->dev, "failed to read chip id %d", ret);
21 return ret;
22 }
23
24 switch (mors->chip_id) {
25 case (CHIP_ID_MM8108):
26 mors->regs = &mm8108_regs;
27 mors->hif.ops = &mm81x_yaps_ops;
28 break;
29 default:
30 return -ENODEV;
31 }
32
33 return ret;
34 }
35
mm81x_core_init_mac_addr(struct mm81x * mors)36 static void mm81x_core_init_mac_addr(struct mm81x *mors)
37 {
38 int ret = mm81x_hw_otp_get_mac_addr(mors);
39
40 if (ret || !is_valid_ether_addr(mors->macaddr))
41 eth_random_addr(mors->macaddr);
42 }
43
mm81x_core_get_fw_path(u32 chip_id,u32 fw_ver)44 char *mm81x_core_get_fw_path(u32 chip_id, u32 fw_ver)
45 {
46 const char *fw_base;
47
48 switch (chip_id) {
49 case CHIP_ID_MM8108:
50 fw_base = MM8108_FW_BASE;
51 break;
52 default:
53 return NULL;
54 }
55
56 return kasprintf(GFP_KERNEL, MM81X_FW_DIR "/v%u/%s" MM81X_FW_EXT,
57 fw_ver, fw_base);
58 }
59 EXPORT_SYMBOL_GPL(mm81x_core_get_fw_path);
60
mm81x_core_alloc(size_t priv_size,struct device * dev)61 struct mm81x *mm81x_core_alloc(size_t priv_size, struct device *dev)
62 {
63 return mm81x_mac_alloc(priv_size, dev);
64 }
65 EXPORT_SYMBOL_GPL(mm81x_core_alloc);
66
mm81x_core_init(struct mm81x * mors)67 int mm81x_core_init(struct mm81x *mors)
68 {
69 int ret;
70
71 set_bit(MM81X_STATE_CHIP_UNRESPONSIVE, &mors->state_flags);
72 set_bit(MM81X_STATE_RELOAD_FW_AFTER_START, &mors->state_flags);
73
74 mm81x_core_init_mac_addr(mors);
75
76 ret = mm81x_core_attach_regs(mors);
77 if (ret)
78 return ret;
79
80 mors->chip_wq = create_singlethread_workqueue("chip_wq");
81 if (!mors->chip_wq)
82 return -ENOMEM;
83
84 mors->net_wq = create_singlethread_workqueue("net_wq");
85 if (!mors->net_wq) {
86 ret = -ENOMEM;
87 goto err_chip_wq;
88 }
89
90 ret = mm81x_hif_init(mors);
91 if (ret)
92 goto err_wqs;
93
94 return 0;
95
96 err_wqs:
97 flush_workqueue(mors->net_wq);
98 destroy_workqueue(mors->net_wq);
99
100 err_chip_wq:
101 flush_workqueue(mors->chip_wq);
102 destroy_workqueue(mors->chip_wq);
103
104 return ret;
105 }
106 EXPORT_SYMBOL_GPL(mm81x_core_init);
107
mm81x_core_register(struct mm81x * mors)108 int mm81x_core_register(struct mm81x *mors)
109 {
110 return mm81x_mac_register(mors);
111 }
112 EXPORT_SYMBOL_GPL(mm81x_core_register);
113
mm81x_core_unregister(struct mm81x * mors)114 void mm81x_core_unregister(struct mm81x *mors)
115 {
116 mm81x_mac_unregister(mors);
117 }
118 EXPORT_SYMBOL_GPL(mm81x_core_unregister);
119
mm81x_core_deinit(struct mm81x * mors)120 void mm81x_core_deinit(struct mm81x *mors)
121 {
122 mm81x_hif_finish(mors);
123 flush_workqueue(mors->net_wq);
124 destroy_workqueue(mors->net_wq);
125 flush_workqueue(mors->chip_wq);
126 destroy_workqueue(mors->chip_wq);
127 }
128 EXPORT_SYMBOL_GPL(mm81x_core_deinit);
129
mm81x_core_free(struct mm81x * mors)130 void mm81x_core_free(struct mm81x *mors)
131 {
132 mm81x_mac_free(mors);
133 }
134 EXPORT_SYMBOL_GPL(mm81x_core_free);
135
136 MODULE_AUTHOR("Morse Micro");
137 MODULE_DESCRIPTION("Driver support for Morse Micro MM81X core");
138 MODULE_LICENSE("Dual BSD/GPL");
139