// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2026 Morse Micro
 */
#include <linux/module.h>
#include "core.h"
#include "bus.h"
#include "hif.h"
#include "mac.h"

static int mm81x_core_attach_regs(struct mm81x *mors)
{
	int ret = 0;

	mm81x_claim_bus(mors);
	ret = mm81x_reg32_read(mors, MM8108_REG_CHIP_ID, &mors->chip_id);
	mm81x_release_bus(mors);

	if (ret < 0) {
		dev_err(mors->dev, "failed to read chip id %d", ret);
		return ret;
	}

	switch (mors->chip_id) {
	case (CHIP_ID_MM8108):
		mors->regs = &mm8108_regs;
		mors->hif.ops = &mm81x_yaps_ops;
		break;
	default:
		return -ENODEV;
	}

	return ret;
}

static void mm81x_core_init_mac_addr(struct mm81x *mors)
{
	int ret = mm81x_hw_otp_get_mac_addr(mors);

	if (ret || !is_valid_ether_addr(mors->macaddr))
		eth_random_addr(mors->macaddr);
}

char *mm81x_core_get_fw_path(u32 chip_id, u32 fw_ver)
{
	const char *fw_base;

	switch (chip_id) {
	case CHIP_ID_MM8108:
		fw_base = MM8108_FW_BASE;
		break;
	default:
		return NULL;
	}

	return kasprintf(GFP_KERNEL, MM81X_FW_DIR "/v%u/%s" MM81X_FW_EXT,
			 fw_ver, fw_base);
}
EXPORT_SYMBOL_GPL(mm81x_core_get_fw_path);

struct mm81x *mm81x_core_alloc(size_t priv_size, struct device *dev)
{
	return mm81x_mac_alloc(priv_size, dev);
}
EXPORT_SYMBOL_GPL(mm81x_core_alloc);

int mm81x_core_init(struct mm81x *mors)
{
	int ret;

	set_bit(MM81X_STATE_CHIP_UNRESPONSIVE, &mors->state_flags);
	set_bit(MM81X_STATE_RELOAD_FW_AFTER_START, &mors->state_flags);

	mm81x_core_init_mac_addr(mors);

	ret = mm81x_core_attach_regs(mors);
	if (ret)
		return ret;

	mors->chip_wq = create_singlethread_workqueue("chip_wq");
	if (!mors->chip_wq)
		return -ENOMEM;

	mors->net_wq = create_singlethread_workqueue("net_wq");
	if (!mors->net_wq) {
		ret = -ENOMEM;
		goto err_chip_wq;
	}

	ret = mm81x_hif_init(mors);
	if (ret)
		goto err_wqs;

	return 0;

err_wqs:
	flush_workqueue(mors->net_wq);
	destroy_workqueue(mors->net_wq);

err_chip_wq:
	flush_workqueue(mors->chip_wq);
	destroy_workqueue(mors->chip_wq);

	return ret;
}
EXPORT_SYMBOL_GPL(mm81x_core_init);

int mm81x_core_register(struct mm81x *mors)
{
	return mm81x_mac_register(mors);
}
EXPORT_SYMBOL_GPL(mm81x_core_register);

void mm81x_core_unregister(struct mm81x *mors)
{
	mm81x_mac_unregister(mors);
}
EXPORT_SYMBOL_GPL(mm81x_core_unregister);

void mm81x_core_deinit(struct mm81x *mors)
{
	mm81x_hif_finish(mors);
	flush_workqueue(mors->net_wq);
	destroy_workqueue(mors->net_wq);
	flush_workqueue(mors->chip_wq);
	destroy_workqueue(mors->chip_wq);
}
EXPORT_SYMBOL_GPL(mm81x_core_deinit);

void mm81x_core_free(struct mm81x *mors)
{
	mm81x_mac_free(mors);
}
EXPORT_SYMBOL_GPL(mm81x_core_free);

MODULE_AUTHOR("Morse Micro");
MODULE_DESCRIPTION("Driver support for Morse Micro MM81X core");
MODULE_LICENSE("Dual BSD/GPL");