linux/drivers/mfd/sm501.c

// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/mfd/sm501.c
 *
 * Copyright (C) 2006 Simtec Electronics
 *	Ben Dooks <[email protected]>
 *	Vincent Sanders <[email protected]>
 *
 * SM501 MFD driver
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/platform_data/i2c-gpio.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/slab.h>

#include <linux/sm501.h>
#include <linux/sm501-regs.h>
#include <linux/serial_8250.h>

#include <linux/io.h>

struct sm501_device {};

struct sm501_gpio;

#ifdef CONFIG_MFD_SM501_GPIO
#include <linux/gpio.h>

struct sm501_gpio_chip {};

struct sm501_gpio {};
#else
struct sm501_gpio {
	/* no gpio support, empty definition for sm501_devdata. */
};
#endif

struct sm501_devdata {};


#define MHZ

#ifdef DEBUG
static const unsigned int div_tab[] = {
	[0]		= 1,
	[1]		= 2,
	[2]		= 4,
	[3]		= 8,
	[4]		= 16,
	[5]		= 32,
	[6]		= 64,
	[7]		= 128,
	[8]		= 3,
	[9]		= 6,
	[10]	        = 12,
	[11]		= 24,
	[12]		= 48,
	[13]		= 96,
	[14]		= 192,
	[15]		= 384,
	[16]		= 5,
	[17]		= 10,
	[18]		= 20,
	[19]		= 40,
	[20]		= 80,
	[21]		= 160,
	[22]		= 320,
	[23]		= 604,
};

static unsigned long decode_div(unsigned long pll2, unsigned long val,
				unsigned int lshft, unsigned int selbit,
				unsigned long mask)
{
	if (val & selbit)
		pll2 = 288 * MHZ;

	return pll2 / div_tab[(val >> lshft) & mask];
}

#define fmt_freq

/* sm501_dump_clk
 *
 * Print out the current clock configuration for the device
*/

static void sm501_dump_clk(struct sm501_devdata *sm)
{
	unsigned long misct = smc501_readl(sm->regs + SM501_MISC_TIMING);
	unsigned long pm0 = smc501_readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
	unsigned long pm1 = smc501_readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
	unsigned long pmc = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
	unsigned long sdclk0, sdclk1;
	unsigned long pll2 = 0;

	switch (misct & 0x30) {
	case 0x00:
		pll2 = 336 * MHZ;
		break;
	case 0x10:
		pll2 = 288 * MHZ;
		break;
	case 0x20:
		pll2 = 240 * MHZ;
		break;
	case 0x30:
		pll2 = 192 * MHZ;
		break;
	}

	sdclk0 = (misct & (1<<12)) ? pll2 : 288 * MHZ;
	sdclk0 /= div_tab[((misct >> 8) & 0xf)];

	sdclk1 = (misct & (1<<20)) ? pll2 : 288 * MHZ;
	sdclk1 /= div_tab[((misct >> 16) & 0xf)];

	dev_dbg(sm->dev, "MISCT=%08lx, PM0=%08lx, PM1=%08lx\n",
		misct, pm0, pm1);

	dev_dbg(sm->dev, "PLL2 = %ld.%ld MHz (%ld), SDCLK0=%08lx, SDCLK1=%08lx\n",
		fmt_freq(pll2), sdclk0, sdclk1);

	dev_dbg(sm->dev, "SDRAM: PM0=%ld, PM1=%ld\n", sdclk0, sdclk1);

	dev_dbg(sm->dev, "PM0[%c]: "
		 "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
		 "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
		 (pmc & 3 ) == 0 ? '*' : '-',
		 fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31)),
		 fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15)),
		 fmt_freq(decode_div(pll2, pm0, 8,  1<<12, 15)),
		 fmt_freq(decode_div(pll2, pm0, 0,  1<<4,  15)));

	dev_dbg(sm->dev, "PM1[%c]: "
		"P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
		"M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
		(pmc & 3 ) == 1 ? '*' : '-',
		fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31)),
		fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15)),
		fmt_freq(decode_div(pll2, pm1, 8,  1<<12, 15)),
		fmt_freq(decode_div(pll2, pm1, 0,  1<<4,  15)));
}

static void sm501_dump_regs(struct sm501_devdata *sm)
{
	void __iomem *regs = sm->regs;

	dev_info(sm->dev, "System Control   %08x\n",
			smc501_readl(regs + SM501_SYSTEM_CONTROL));
	dev_info(sm->dev, "Misc Control     %08x\n",
			smc501_readl(regs + SM501_MISC_CONTROL));
	dev_info(sm->dev, "GPIO Control Low %08x\n",
			smc501_readl(regs + SM501_GPIO31_0_CONTROL));
	dev_info(sm->dev, "GPIO Control Hi  %08x\n",
			smc501_readl(regs + SM501_GPIO63_32_CONTROL));
	dev_info(sm->dev, "DRAM Control     %08x\n",
			smc501_readl(regs + SM501_DRAM_CONTROL));
	dev_info(sm->dev, "Arbitration Ctrl %08x\n",
			smc501_readl(regs + SM501_ARBTRTN_CONTROL));
	dev_info(sm->dev, "Misc Timing      %08x\n",
			smc501_readl(regs + SM501_MISC_TIMING));
}

static void sm501_dump_gate(struct sm501_devdata *sm)
{
	dev_info(sm->dev, "CurrentGate      %08x\n",
			smc501_readl(sm->regs + SM501_CURRENT_GATE));
	dev_info(sm->dev, "CurrentClock     %08x\n",
			smc501_readl(sm->regs + SM501_CURRENT_CLOCK));
	dev_info(sm->dev, "PowerModeControl %08x\n",
			smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL));
}

#else
static inline void sm501_dump_gate(struct sm501_devdata *sm) {}
static inline void sm501_dump_regs(struct sm501_devdata *sm) {}
static inline void sm501_dump_clk(struct sm501_devdata *sm) {}
#endif

/* sm501_sync_regs
 *
 * ensure the
*/

static void sm501_sync_regs(struct sm501_devdata *sm)
{}

static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay)
{}

/* sm501_misc_control
 *
 * alters the miscellaneous control parameters
*/

int sm501_misc_control(struct device *dev,
		       unsigned long set, unsigned long clear)
{}

EXPORT_SYMBOL_GPL();

/* sm501_modify_reg
 *
 * Modify a register in the SM501 which may be shared with other
 * drivers.
*/

unsigned long sm501_modify_reg(struct device *dev,
			       unsigned long reg,
			       unsigned long set,
			       unsigned long clear)
{}

EXPORT_SYMBOL_GPL();

/* sm501_unit_power
 *
 * alters the power active gate to set specific units on or off
 */

int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
{}

EXPORT_SYMBOL_GPL();

/* clock value structure. */
struct sm501_clock {};

/* sm501_calc_clock
 *
 * Calculates the nearest discrete clock frequency that
 * can be achieved with the specified input clock.
 *   the maximum divisor is 3 or 5
 */

static int sm501_calc_clock(unsigned long freq,
			    struct sm501_clock *clock,
			    int max_div,
			    unsigned long mclk,
			    long *best_diff)
{}

/* sm501_calc_pll
 *
 * Calculates the nearest discrete clock frequency that can be
 * achieved using the programmable PLL.
 *   the maximum divisor is 3 or 5
 */

static unsigned long sm501_calc_pll(unsigned long freq,
					struct sm501_clock *clock,
					int max_div)
{}

/* sm501_select_clock
 *
 * Calculates the nearest discrete clock frequency that can be
 * achieved using the 288MHz and 336MHz PLLs.
 *   the maximum divisor is 3 or 5
 */

static unsigned long sm501_select_clock(unsigned long freq,
					struct sm501_clock *clock,
					int max_div)
{}

/* sm501_set_clock
 *
 * set one of the four clock sources to the closest available frequency to
 *  the one specified
*/

unsigned long sm501_set_clock(struct device *dev,
			      int clksrc,
			      unsigned long req_freq)
{}

EXPORT_SYMBOL_GPL();

/* sm501_find_clock
 *
 * finds the closest available frequency for a given clock
*/

unsigned long sm501_find_clock(struct device *dev,
			       int clksrc,
			       unsigned long req_freq)
{}

EXPORT_SYMBOL_GPL();

static struct sm501_device *to_sm_device(struct platform_device *pdev)
{}

/* sm501_device_release
 *
 * A release function for the platform devices we create to allow us to
 * free any items we allocated
*/

static void sm501_device_release(struct device *dev)
{}

/* sm501_create_subdev
 *
 * Create a skeleton platform device with resources for passing to a
 * sub-driver
*/

static struct platform_device *
sm501_create_subdev(struct sm501_devdata *sm, char *name,
		    unsigned int res_count, unsigned int platform_data_size)
{}

/* sm501_register_device
 *
 * Register a platform device created with sm501_create_subdev()
*/

static int sm501_register_device(struct sm501_devdata *sm,
				 struct platform_device *pdev)
{}

/* sm501_create_subio
 *
 * Fill in an IO resource for a sub device
*/

static void sm501_create_subio(struct sm501_devdata *sm,
			       struct resource *res,
			       resource_size_t offs,
			       resource_size_t size)
{}

/* sm501_create_mem
 *
 * Fill in an MEM resource for a sub device
*/

static void sm501_create_mem(struct sm501_devdata *sm,
			     struct resource *res,
			     resource_size_t *offs,
			     resource_size_t size)
{}

/* sm501_create_irq
 *
 * Fill in an IRQ resource for a sub device
*/

static void sm501_create_irq(struct sm501_devdata *sm,
			     struct resource *res)
{}

static int sm501_register_usbhost(struct sm501_devdata *sm,
				  resource_size_t *mem_avail)
{}

static void sm501_setup_uart_data(struct sm501_devdata *sm,
				  struct plat_serial8250_port *uart_data,
				  unsigned int offset)
{}

static int sm501_register_uart(struct sm501_devdata *sm, int devices)
{}

static int sm501_register_display(struct sm501_devdata *sm,
				  resource_size_t *mem_avail)
{}

#ifdef CONFIG_MFD_SM501_GPIO

static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio)
{}

static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)

{}

static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
				   unsigned long bit)
{}

static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)

{}

static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
{}

static int sm501_gpio_output(struct gpio_chip *chip,
			     unsigned offset, int value)
{}

static const struct gpio_chip gpio_chip_template =;

static int sm501_gpio_register_chip(struct sm501_devdata *sm,
					      struct sm501_gpio *gpio,
					      struct sm501_gpio_chip *chip)
{}

static int sm501_register_gpio(struct sm501_devdata *sm)
{}

static void sm501_gpio_remove(struct sm501_devdata *sm)
{}

static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
{}
#else
static inline int sm501_register_gpio(struct sm501_devdata *sm)
{
	return 0;
}

static inline void sm501_gpio_remove(struct sm501_devdata *sm)
{
}

static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
{
	return 0;
}
#endif

static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
					    struct sm501_platdata_gpio_i2c *iic)
{}

static int sm501_register_gpio_i2c(struct sm501_devdata *sm,
				   struct sm501_platdata *pdata)
{}

/* dbg_regs_show
 *
 * Debug attribute to attach to parent device to show core registers
*/

static ssize_t dbg_regs_show(struct device *dev,
			     struct device_attribute *attr, char *buff)
{}


static DEVICE_ATTR_RO(dbg_regs);

/* sm501_init_reg
 *
 * Helper function for the init code to setup a register
 *
 * clear the bits which are set in r->mask, and then set
 * the bits set in r->set.
*/

static inline void sm501_init_reg(struct sm501_devdata *sm,
				  unsigned long reg,
				  struct sm501_reg_init *r)
{}

/* sm501_init_regs
 *
 * Setup core register values
*/

static void sm501_init_regs(struct sm501_devdata *sm,
			    struct sm501_initdata *init)
{}

/* Check the PLL sources for the M1CLK and M1XCLK
 *
 * If the M1CLK and M1XCLKs are not sourced from the same PLL, then
 * there is a risk (see errata AB-5) that the SM501 will cease proper
 * function. If this happens, then it is likely the SM501 will
 * hang the system.
*/

static int sm501_check_clocks(struct sm501_devdata *sm)
{}

static unsigned int sm501_mem_local[] =;

/* sm501_init_dev
 *
 * Common init code for an SM501
*/

static int sm501_init_dev(struct sm501_devdata *sm)
{}

static int sm501_plat_probe(struct platform_device *dev)
{}

/* power management support */

static void sm501_set_power(struct sm501_devdata *sm, int on)
{}

static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state)
{}

static int sm501_plat_resume(struct platform_device *pdev)
{}

/* Initialisation data for PCI devices */

static struct sm501_initdata sm501_pci_initdata =;

static struct sm501_platdata_fbsub sm501_pdata_fbsub =;

static struct sm501_platdata_fb sm501_fb_pdata =;

static struct sm501_platdata sm501_pci_platdata =;

static int sm501_pci_probe(struct pci_dev *dev,
				     const struct pci_device_id *id)
{}

static void sm501_remove_sub(struct sm501_devdata *sm,
			     struct sm501_device *smdev)
{}

static void sm501_dev_remove(struct sm501_devdata *sm)
{}

static void sm501_pci_remove(struct pci_dev *dev)
{}

static void sm501_plat_remove(struct platform_device *dev)
{}

static const struct pci_device_id sm501_pci_tbl[] =;

MODULE_DEVICE_TABLE(pci, sm501_pci_tbl);

static struct pci_driver sm501_pci_driver =;

MODULE_ALIAS();

static const struct of_device_id of_sm501_match_tbl[] =;
MODULE_DEVICE_TABLE(of, of_sm501_match_tbl);

static struct platform_driver sm501_plat_driver =;

static int __init sm501_base_init(void)
{}

static void __exit sm501_base_exit(void)
{}

module_init();
module_exit(sm501_base_exit);

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();