/*
 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
 *
 * Permission to use, copy, modify, and/or distribute this software for
 * any purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all copies.
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <linux/kconfig.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <generated/autoconf.h>
#include <linux/delay.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/string.h>
#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
#include <linux/of.h>
 #include <linux/switch.h>
#else
#include <net/switch.h>
#include <linux/ar8216_platform.h>
#endif
#include "sw.h"
#include "ssdk_init.h"
#include "ssdk_plat.h"

#ifdef BOARD_AR71XX

struct switch_dev *old_sw_dev = NULL;
struct net_device	  *sw_attach_dev = NULL;
struct qca_phy_priv qca_priv;

extern int qca_phy_id_chip(struct qca_phy_priv *priv);
extern const struct switch_dev_ops qca_ar8327_sw_ops;
extern int qca_phy_mib_work_start(struct qca_phy_priv *priv);
extern void qca_phy_mib_work_stop(struct qca_phy_priv *priv);

int
ssdk_uci_sw_set_vlan(const struct switch_attr *attr,
                       struct switch_val *val)
{
	if(old_sw_dev) {
		struct switch_dev_ops *ops = old_sw_dev->ops;
		if(ops) {
			struct switch_attrlist attr_global = ops->attr_global;
			int i = 0;
			struct switch_attr *g_attr = attr_global.attr;
			for(i = 0; i < attr_global.n_attr; i++) {
				if(!strcmp(g_attr[i].name, "enable_vlan") &&
					g_attr[i].set) {
					g_attr[i].set(old_sw_dev, attr, val);
					break;
				}
			}
		}
	}
	return 0;
}

int
ssdk_uci_sw_set_vid(const struct switch_attr *attr,
                       struct switch_val *val)
{
	if(old_sw_dev) {
		struct switch_dev_ops *ops = old_sw_dev->ops;
		if(ops) {
			struct switch_attrlist attr_vlan = ops->attr_vlan;
			int i = 0;
			struct switch_attr *v_attr = attr_vlan.attr;
			for(i = 0; i < attr_vlan.n_attr; i++) {
				if(!strcmp(v_attr[i].name, "vid") &&
					v_attr[i].set) {
					v_attr[i].set(old_sw_dev, attr, val);
					break;
				}
			}
		}
	}
	return 0;
}


int
ssdk_uci_sw_set_pvid(int port, int vlan)
{
	if(old_sw_dev) {
		struct switch_dev_ops *ops = old_sw_dev->ops;
		if(ops && ops->set_port_pvid) {
			ops->set_port_pvid(old_sw_dev, port, vlan);
		}
	}
	return 0;
}

int
ssdk_uci_sw_set_ports(struct switch_val *val)
{
	if(old_sw_dev) {
		struct switch_dev_ops *ops = old_sw_dev->ops;
		if(ops && ops->set_vlan_ports) {
			ops->set_vlan_ports(old_sw_dev, val);
		}
	}
	return 0;
}
#endif


