162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/types.h>
362306a36Sopenharmony_ci#include <linux/init.h>
462306a36Sopenharmony_ci#include <linux/delay.h>
562306a36Sopenharmony_ci#include <linux/kernel.h>
662306a36Sopenharmony_ci#include <linux/interrupt.h>
762306a36Sopenharmony_ci#include <linux/spinlock.h>
862306a36Sopenharmony_ci#include <linux/of_irq.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/pmac_feature.h>
1162306a36Sopenharmony_ci#include <asm/pmac_pfunc.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#undef DEBUG
1462306a36Sopenharmony_ci#ifdef DEBUG
1562306a36Sopenharmony_ci#define DBG(fmt...)	printk(fmt)
1662306a36Sopenharmony_ci#else
1762306a36Sopenharmony_ci#define DBG(fmt...)
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic irqreturn_t macio_gpio_irq(int irq, void *data)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	pmf_do_irq(data);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	return IRQ_HANDLED;
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int macio_do_gpio_irq_enable(struct pmf_function *func)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	unsigned int irq = irq_of_parse_and_map(func->node, 0);
3062306a36Sopenharmony_ci	if (!irq)
3162306a36Sopenharmony_ci		return -EINVAL;
3262306a36Sopenharmony_ci	return request_irq(irq, macio_gpio_irq, 0, func->node->name, func);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int macio_do_gpio_irq_disable(struct pmf_function *func)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	unsigned int irq = irq_of_parse_and_map(func->node, 0);
3862306a36Sopenharmony_ci	if (!irq)
3962306a36Sopenharmony_ci		return -EINVAL;
4062306a36Sopenharmony_ci	free_irq(irq, func);
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int macio_do_gpio_write(PMF_STD_ARGS, u8 value, u8 mask)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	u8 __iomem *addr = (u8 __iomem *)func->driver_data;
4762306a36Sopenharmony_ci	unsigned long flags;
4862306a36Sopenharmony_ci	u8 tmp;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* Check polarity */
5162306a36Sopenharmony_ci	if (args && args->count && !args->u[0].v)
5262306a36Sopenharmony_ci		value = ~value;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* Toggle the GPIO */
5562306a36Sopenharmony_ci	raw_spin_lock_irqsave(&feature_lock, flags);
5662306a36Sopenharmony_ci	tmp = readb(addr);
5762306a36Sopenharmony_ci	tmp = (tmp & ~mask) | (value & mask);
5862306a36Sopenharmony_ci	DBG("Do write 0x%02x to GPIO %pOF (%p)\n",
5962306a36Sopenharmony_ci	    tmp, func->node, addr);
6062306a36Sopenharmony_ci	writeb(tmp, addr);
6162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&feature_lock, flags);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return 0;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int macio_do_gpio_read(PMF_STD_ARGS, u8 mask, int rshift, u8 xor)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	u8 __iomem *addr = (u8 __iomem *)func->driver_data;
6962306a36Sopenharmony_ci	u32 value;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Check if we have room for reply */
7262306a36Sopenharmony_ci	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
7362306a36Sopenharmony_ci		return -EINVAL;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	value = readb(addr);
7662306a36Sopenharmony_ci	*args->u[0].p = ((value & mask) >> rshift) ^ xor;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return 0;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int macio_do_delay(PMF_STD_ARGS, u32 duration)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	/* assume we can sleep ! */
8462306a36Sopenharmony_ci	msleep((duration + 999) / 1000);
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic struct pmf_handlers macio_gpio_handlers = {
8962306a36Sopenharmony_ci	.irq_enable	= macio_do_gpio_irq_enable,
9062306a36Sopenharmony_ci	.irq_disable	= macio_do_gpio_irq_disable,
9162306a36Sopenharmony_ci	.write_gpio	= macio_do_gpio_write,
9262306a36Sopenharmony_ci	.read_gpio	= macio_do_gpio_read,
9362306a36Sopenharmony_ci	.delay		= macio_do_delay,
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void __init macio_gpio_init_one(struct macio_chip *macio)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct device_node *gparent, *gp;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/*
10162306a36Sopenharmony_ci	 * Find the "gpio" parent node
10262306a36Sopenharmony_ci	 */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	for_each_child_of_node(macio->of_node, gparent)
10562306a36Sopenharmony_ci		if (of_node_name_eq(gparent, "gpio"))
10662306a36Sopenharmony_ci			break;
10762306a36Sopenharmony_ci	if (gparent == NULL)
10862306a36Sopenharmony_ci		return;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	DBG("Installing GPIO functions for macio %pOF\n",
11162306a36Sopenharmony_ci	    macio->of_node);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/*
11462306a36Sopenharmony_ci	 * Ok, got one, we dont need anything special to track them down, so
11562306a36Sopenharmony_ci	 * we just create them all
11662306a36Sopenharmony_ci	 */
11762306a36Sopenharmony_ci	for_each_child_of_node(gparent, gp) {
11862306a36Sopenharmony_ci		const u32 *reg = of_get_property(gp, "reg", NULL);
11962306a36Sopenharmony_ci		unsigned long offset;
12062306a36Sopenharmony_ci		if (reg == NULL)
12162306a36Sopenharmony_ci			continue;
12262306a36Sopenharmony_ci		offset = *reg;
12362306a36Sopenharmony_ci		/* Deal with old style device-tree. We can safely hard code the
12462306a36Sopenharmony_ci		 * offset for now too even if it's a bit gross ...
12562306a36Sopenharmony_ci		 */
12662306a36Sopenharmony_ci		if (offset < 0x50)
12762306a36Sopenharmony_ci			offset += 0x50;
12862306a36Sopenharmony_ci		offset += (unsigned long)macio->base;
12962306a36Sopenharmony_ci		pmf_register_driver(gp, &macio_gpio_handlers, (void *)offset);
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	DBG("Calling initial GPIO functions for macio %pOF\n",
13362306a36Sopenharmony_ci	    macio->of_node);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* And now we run all the init ones */
13662306a36Sopenharmony_ci	for_each_child_of_node(gparent, gp)
13762306a36Sopenharmony_ci		pmf_do_functions(gp, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	of_node_put(gparent);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Note: We do not at this point implement the "at sleep" or "at wake"
14262306a36Sopenharmony_ci	 * functions. I yet to find any for GPIOs anyway
14362306a36Sopenharmony_ci	 */
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int macio_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
14962306a36Sopenharmony_ci	unsigned long flags;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	raw_spin_lock_irqsave(&feature_lock, flags);
15262306a36Sopenharmony_ci	MACIO_OUT32(offset, (MACIO_IN32(offset) & ~mask) | (value & mask));
15362306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&feature_lock, flags);
15462306a36Sopenharmony_ci	return 0;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic int macio_do_read_reg32(PMF_STD_ARGS, u32 offset)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* Check if we have room for reply */
16262306a36Sopenharmony_ci	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
16362306a36Sopenharmony_ci		return -EINVAL;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	*args->u[0].p = MACIO_IN32(offset);
16662306a36Sopenharmony_ci	return 0;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int macio_do_write_reg8(PMF_STD_ARGS, u32 offset, u8 value, u8 mask)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
17262306a36Sopenharmony_ci	unsigned long flags;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&feature_lock, flags);
17562306a36Sopenharmony_ci	MACIO_OUT8(offset, (MACIO_IN8(offset) & ~mask) | (value & mask));
17662306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&feature_lock, flags);
17762306a36Sopenharmony_ci	return 0;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int macio_do_read_reg8(PMF_STD_ARGS, u32 offset)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Check if we have room for reply */
18562306a36Sopenharmony_ci	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
18662306a36Sopenharmony_ci		return -EINVAL;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	*((u8 *)(args->u[0].p)) = MACIO_IN8(offset);
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int macio_do_read_reg32_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
19362306a36Sopenharmony_ci				    u32 shift, u32 xor)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* Check if we have room for reply */
19862306a36Sopenharmony_ci	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
19962306a36Sopenharmony_ci		return -EINVAL;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	*args->u[0].p = ((MACIO_IN32(offset) & mask) >> shift) ^ xor;
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int macio_do_read_reg8_msrx(PMF_STD_ARGS, u32 offset, u32 mask,
20662306a36Sopenharmony_ci				   u32 shift, u32 xor)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* Check if we have room for reply */
21162306a36Sopenharmony_ci	if (args == NULL || args->count == 0 || args->u[0].p == NULL)
21262306a36Sopenharmony_ci		return -EINVAL;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	*((u8 *)(args->u[0].p)) = ((MACIO_IN8(offset) & mask) >> shift) ^ xor;
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int macio_do_write_reg32_slm(PMF_STD_ARGS, u32 offset, u32 shift,
21962306a36Sopenharmony_ci				    u32 mask)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
22262306a36Sopenharmony_ci	unsigned long flags;
22362306a36Sopenharmony_ci	u32 tmp, val;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Check args */
22662306a36Sopenharmony_ci	if (args == NULL || args->count == 0)
22762306a36Sopenharmony_ci		return -EINVAL;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&feature_lock, flags);
23062306a36Sopenharmony_ci	tmp = MACIO_IN32(offset);
23162306a36Sopenharmony_ci	val = args->u[0].v << shift;
23262306a36Sopenharmony_ci	tmp = (tmp & ~mask) | (val & mask);
23362306a36Sopenharmony_ci	MACIO_OUT32(offset, tmp);
23462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&feature_lock, flags);
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int macio_do_write_reg8_slm(PMF_STD_ARGS, u32 offset, u32 shift,
23962306a36Sopenharmony_ci				   u32 mask)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct macio_chip *macio = func->driver_data;
24262306a36Sopenharmony_ci	unsigned long flags;
24362306a36Sopenharmony_ci	u32 tmp, val;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* Check args */
24662306a36Sopenharmony_ci	if (args == NULL || args->count == 0)
24762306a36Sopenharmony_ci		return -EINVAL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&feature_lock, flags);
25062306a36Sopenharmony_ci	tmp = MACIO_IN8(offset);
25162306a36Sopenharmony_ci	val = args->u[0].v << shift;
25262306a36Sopenharmony_ci	tmp = (tmp & ~mask) | (val & mask);
25362306a36Sopenharmony_ci	MACIO_OUT8(offset, tmp);
25462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&feature_lock, flags);
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic struct pmf_handlers macio_mmio_handlers = {
25962306a36Sopenharmony_ci	.write_reg32		= macio_do_write_reg32,
26062306a36Sopenharmony_ci	.read_reg32		= macio_do_read_reg32,
26162306a36Sopenharmony_ci	.write_reg8		= macio_do_write_reg8,
26262306a36Sopenharmony_ci	.read_reg8		= macio_do_read_reg8,
26362306a36Sopenharmony_ci	.read_reg32_msrx	= macio_do_read_reg32_msrx,
26462306a36Sopenharmony_ci	.read_reg8_msrx		= macio_do_read_reg8_msrx,
26562306a36Sopenharmony_ci	.write_reg32_slm	= macio_do_write_reg32_slm,
26662306a36Sopenharmony_ci	.write_reg8_slm		= macio_do_write_reg8_slm,
26762306a36Sopenharmony_ci	.delay			= macio_do_delay,
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void __init macio_mmio_init_one(struct macio_chip *macio)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	DBG("Installing MMIO functions for macio %pOF\n",
27362306a36Sopenharmony_ci	    macio->of_node);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	pmf_register_driver(macio->of_node, &macio_mmio_handlers, macio);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic struct device_node *unin_hwclock;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int unin_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	unsigned long flags;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&feature_lock, flags);
28562306a36Sopenharmony_ci	/* This is fairly bogus in darwin, but it should work for our needs
28662306a36Sopenharmony_ci	 * implemeted that way:
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci	UN_OUT(offset, (UN_IN(offset) & ~mask) | (value & mask));
28962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&feature_lock, flags);
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic struct pmf_handlers unin_mmio_handlers = {
29562306a36Sopenharmony_ci	.write_reg32		= unin_do_write_reg32,
29662306a36Sopenharmony_ci	.delay			= macio_do_delay,
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void __init uninorth_install_pfunc(void)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct device_node *np;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	DBG("Installing functions for UniN %pOF\n",
30462306a36Sopenharmony_ci	    uninorth_node);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/*
30762306a36Sopenharmony_ci	 * Install handlers for the bridge itself
30862306a36Sopenharmony_ci	 */
30962306a36Sopenharmony_ci	pmf_register_driver(uninorth_node, &unin_mmio_handlers, NULL);
31062306a36Sopenharmony_ci	pmf_do_functions(uninorth_node, NULL, 0, PMF_FLAGS_ON_INIT, NULL);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/*
31462306a36Sopenharmony_ci	 * Install handlers for the hwclock child if any
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	for (np = NULL; (np = of_get_next_child(uninorth_node, np)) != NULL;)
31762306a36Sopenharmony_ci		if (of_node_name_eq(np, "hw-clock")) {
31862306a36Sopenharmony_ci			unin_hwclock = np;
31962306a36Sopenharmony_ci			break;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci	if (unin_hwclock) {
32262306a36Sopenharmony_ci		DBG("Installing functions for UniN clock %pOF\n",
32362306a36Sopenharmony_ci		    unin_hwclock);
32462306a36Sopenharmony_ci		pmf_register_driver(unin_hwclock, &unin_mmio_handlers, NULL);
32562306a36Sopenharmony_ci		pmf_do_functions(unin_hwclock, NULL, 0, PMF_FLAGS_ON_INIT,
32662306a36Sopenharmony_ci				 NULL);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/* We export this as the SMP code might init us early */
33162306a36Sopenharmony_ciint __init pmac_pfunc_base_install(void)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	static int pfbase_inited;
33462306a36Sopenharmony_ci	int i;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (pfbase_inited)
33762306a36Sopenharmony_ci		return 0;
33862306a36Sopenharmony_ci	pfbase_inited = 1;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!machine_is(powermac))
34162306a36Sopenharmony_ci		return 0;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	DBG("Installing base platform functions...\n");
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/*
34662306a36Sopenharmony_ci	 * Locate mac-io chips and install handlers
34762306a36Sopenharmony_ci	 */
34862306a36Sopenharmony_ci	for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
34962306a36Sopenharmony_ci		if (macio_chips[i].of_node) {
35062306a36Sopenharmony_ci			macio_mmio_init_one(&macio_chips[i]);
35162306a36Sopenharmony_ci			macio_gpio_init_one(&macio_chips[i]);
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/*
35662306a36Sopenharmony_ci	 * Install handlers for northbridge and direct mapped hwclock
35762306a36Sopenharmony_ci	 * if any. We do not implement the config space access callback
35862306a36Sopenharmony_ci	 * which is only ever used for functions that we do not call in
35962306a36Sopenharmony_ci	 * the current driver (enabling/disabling cells in U2, mostly used
36062306a36Sopenharmony_ci	 * to restore the PCI settings, we do that differently)
36162306a36Sopenharmony_ci	 */
36262306a36Sopenharmony_ci	if (uninorth_node && uninorth_base)
36362306a36Sopenharmony_ci		uninorth_install_pfunc();
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	DBG("All base functions installed\n");
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_cimachine_arch_initcall(powermac, pmac_pfunc_base_install);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci#ifdef CONFIG_PM
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/* Those can be called by pmac_feature. Ultimately, I should use a sysdev
37462306a36Sopenharmony_ci * or a device, but for now, that's good enough until I sort out some
37562306a36Sopenharmony_ci * ordering issues. Also, we do not bother with GPIOs, as so far I yet have
37662306a36Sopenharmony_ci * to see a case where a GPIO function has the on-suspend or on-resume bit
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_civoid pmac_pfunc_base_suspend(void)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	int i;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
38362306a36Sopenharmony_ci		if (macio_chips[i].of_node)
38462306a36Sopenharmony_ci			pmf_do_functions(macio_chips[i].of_node, NULL, 0,
38562306a36Sopenharmony_ci					 PMF_FLAGS_ON_SLEEP, NULL);
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	if (uninorth_node)
38862306a36Sopenharmony_ci		pmf_do_functions(uninorth_node, NULL, 0,
38962306a36Sopenharmony_ci				 PMF_FLAGS_ON_SLEEP, NULL);
39062306a36Sopenharmony_ci	if (unin_hwclock)
39162306a36Sopenharmony_ci		pmf_do_functions(unin_hwclock, NULL, 0,
39262306a36Sopenharmony_ci				 PMF_FLAGS_ON_SLEEP, NULL);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_civoid pmac_pfunc_base_resume(void)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	int i;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (unin_hwclock)
40062306a36Sopenharmony_ci		pmf_do_functions(unin_hwclock, NULL, 0,
40162306a36Sopenharmony_ci				 PMF_FLAGS_ON_WAKE, NULL);
40262306a36Sopenharmony_ci	if (uninorth_node)
40362306a36Sopenharmony_ci		pmf_do_functions(uninorth_node, NULL, 0,
40462306a36Sopenharmony_ci				 PMF_FLAGS_ON_WAKE, NULL);
40562306a36Sopenharmony_ci	for (i = 0 ; i < MAX_MACIO_CHIPS; i++) {
40662306a36Sopenharmony_ci		if (macio_chips[i].of_node)
40762306a36Sopenharmony_ci			pmf_do_functions(macio_chips[i].of_node, NULL, 0,
40862306a36Sopenharmony_ci					 PMF_FLAGS_ON_WAKE, NULL);
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci#endif /* CONFIG_PM */
413