/*
 * Copyright 2013-2015 Emilio López
 *
 * Emilio López <emilio@elopez.com.ar>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>


/**
 * sunxi_usb_reset... - reset bits in usb clk registers handling
 */

struct usb_reset_data {
	void __iomem			*reg;
	spinlock_t			*lock;
	struct clk			*clk;
	struct reset_controller_dev	rcdev;
};

static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev,
			      unsigned long id)
{
	struct usb_reset_data *data = container_of(rcdev,
						   struct usb_reset_data,
						   rcdev);
	unsigned long flags;
	u32 reg;

	clk_prepare_enable(data->clk);
	spin_lock_irqsave(data->lock, flags);

	reg = readl(data->reg);
	writel(reg & ~BIT(id), data->reg);

	spin_unlock_irqrestore(data->lock, flags);
	clk_disable_unprepare(data->clk);

	return 0;
}

static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	struct usb_reset_data *data = container_of(rcdev,
						     struct usb_reset_data,
						     rcdev);
	unsigned long flags;
	u32 reg;

	clk_prepare_enable(data->clk);
	spin_lock_irqsave(data->lock, flags);

	reg = readl(data->reg);
	writel(reg | BIT(id), data->reg);

	spin_unlock_irqrestore(data->lock, flags);
	clk_disable_unprepare(data->clk);

	return 0;
}

static const struct reset_control_ops sunxi_usb_reset_ops = {
	.assert		= sunxi_usb_reset_assert,
	.deassert	= sunxi_usb_reset_deassert,
};

/**
 * sunxi_usb_clk_setup() - Setup function for usb gate clocks
 */

#define SUNXI_USB_MAX_SIZE 32

struct usb_clk_data {
	u32 clk_mask;
	u32 reset_mask;
	bool reset_needs_clk;
};

static void __init sunxi_usb_clk_setup(struct device_node *node,
				       const struct usb_clk_data *data,
				       spinlock_t *lock)
{
	struct clk_onecell_data *clk_data;
	struct usb_reset_data *reset_data;
	const char *clk_parent;
	const char *clk_name;
	void __iomem *reg;
	int qty;
	int i = 0;
	int j = 0;

	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
	if (IS_ERR(reg))
		return;

	clk_parent = of_clk_get_parent_name(node, 0);
	if (!clk_parent)
		return;

	/* Worst-case size approximation and memory allocation */
	qty = find_last_bit((unsigned long *)&data->clk_mask,
			    SUNXI_USB_MAX_SIZE);

	clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
	if (!clk_data)
		return;

	clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
	if (!clk_data->clks) {
		kfree(clk_data);
		return;
	}

	for_each_set_bit(i, (unsigned long *)&data->clk_mask,
			 SUNXI_USB_MAX_SIZE) {
		of_property_read_string_index(node, "clock-output-names",
					      j, &clk_name);
		clk_data->clks[i] = clk_register_gate(NULL, clk_name,
						      clk_parent, 0,
						      reg, i, 0, lock);
		WARN_ON(IS_ERR(clk_data->clks[i]));

		j++;
	}

	/* Adjust to the real max */
	clk_data->clk_num = i;

	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

	/* Register a reset controller for usb with reset bits */
	if (data->reset_mask == 0)
		return;

	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
	if (!reset_data)
		return;

	if (data->reset_needs_clk) {
		reset_data->clk = of_clk_get(node, 0);
		if (IS_ERR(reset_data->clk)) {
			pr_err("Could not get clock for reset controls\n");
			kfree(reset_data);
			return;
		}
	}

	reset_data->reg = reg;
	reset_data->lock = lock;
	reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
	reset_data->rcdev.ops = &sunxi_usb_reset_ops;
	reset_data->rcdev.of_node = node;
	reset_controller_register(&reset_data->rcdev);
}

static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst = {
	.clk_mask = BIT(8) | BIT(7) | BIT(6),
	.reset_mask = BIT(2) | BIT(1) | BIT(0),
};

static DEFINE_SPINLOCK(sun4i_a10_usb_lock);

static void __init sun4i_a10_usb_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun4i_a10_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun4i_a10_usb, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup);

static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst = {
	.clk_mask = BIT(8) | BIT(6),
	.reset_mask = BIT(1) | BIT(0),
};

static void __init sun5i_a13_usb_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun5i_a13_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun5i_a13_usb, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup);

static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst = {
	.clk_mask = BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8),
	.reset_mask = BIT(2) | BIT(1) | BIT(0),
};

static void __init sun6i_a31_usb_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun6i_a31_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup);

static const struct usb_clk_data sun8i_a23_usb_clk_data __initconst = {
	.clk_mask = BIT(16) | BIT(11) | BIT(10) | BIT(9) | BIT(8),
	.reset_mask = BIT(2) | BIT(1) | BIT(0),
};

static void __init sun8i_a23_usb_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun8i_a23_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun8i_a23_usb, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup);

static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
	.clk_mask =  BIT(19) | BIT(18) | BIT(17) | BIT(16) |
		     BIT(11) | BIT(10) | BIT(9) | BIT(8),
	.reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
};

static void __init sun8i_h3_usb_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);

static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
	.clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
	.reset_mask = BIT(19) | BIT(18) | BIT(17),
	.reset_needs_clk = 1,
};

static DEFINE_SPINLOCK(a80_usb_mod_lock);

static void __init sun9i_a80_usb_mod_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock);
}
CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup);

static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst = {
	.clk_mask = BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
	.reset_mask = BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
	.reset_needs_clk = 1,
};

static DEFINE_SPINLOCK(a80_usb_phy_lock);

static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
{
	sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
}
CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
