162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* auxio.c: Probing for the Sparc AUXIO register at boot time. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Refactoring for unified NCR/PCIO support 2002 Eric Brower (ebrower@usa.net) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/ioport.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/prom.h> 1762306a36Sopenharmony_ci#include <asm/io.h> 1862306a36Sopenharmony_ci#include <asm/auxio.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_civoid __iomem *auxio_register = NULL; 2162306a36Sopenharmony_ciEXPORT_SYMBOL(auxio_register); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cienum auxio_type { 2462306a36Sopenharmony_ci AUXIO_TYPE_NODEV, 2562306a36Sopenharmony_ci AUXIO_TYPE_SBUS, 2662306a36Sopenharmony_ci AUXIO_TYPE_EBUS 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic enum auxio_type auxio_devtype = AUXIO_TYPE_NODEV; 3062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(auxio_lock); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void __auxio_rmw(u8 bits_on, u8 bits_off, int ebus) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci if (auxio_register) { 3562306a36Sopenharmony_ci unsigned long flags; 3662306a36Sopenharmony_ci u8 regval, newval; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci spin_lock_irqsave(&auxio_lock, flags); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci regval = (ebus ? 4162306a36Sopenharmony_ci (u8) readl(auxio_register) : 4262306a36Sopenharmony_ci sbus_readb(auxio_register)); 4362306a36Sopenharmony_ci newval = regval | bits_on; 4462306a36Sopenharmony_ci newval &= ~bits_off; 4562306a36Sopenharmony_ci if (!ebus) 4662306a36Sopenharmony_ci newval &= ~AUXIO_AUX1_MASK; 4762306a36Sopenharmony_ci if (ebus) 4862306a36Sopenharmony_ci writel((u32) newval, auxio_register); 4962306a36Sopenharmony_ci else 5062306a36Sopenharmony_ci sbus_writeb(newval, auxio_register); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci spin_unlock_irqrestore(&auxio_lock, flags); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void __auxio_set_bit(u8 bit, int on, int ebus) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci u8 bits_on = (ebus ? AUXIO_PCIO_LED : AUXIO_AUX1_LED); 5962306a36Sopenharmony_ci u8 bits_off = 0; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (!on) { 6262306a36Sopenharmony_ci u8 tmp = bits_off; 6362306a36Sopenharmony_ci bits_off = bits_on; 6462306a36Sopenharmony_ci bits_on = tmp; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci __auxio_rmw(bits_on, bits_off, ebus); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid auxio_set_led(int on) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci int ebus = auxio_devtype == AUXIO_TYPE_EBUS; 7262306a36Sopenharmony_ci u8 bit; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci bit = (ebus ? AUXIO_PCIO_LED : AUXIO_AUX1_LED); 7562306a36Sopenharmony_ci __auxio_set_bit(bit, on, ebus); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ciEXPORT_SYMBOL(auxio_set_led); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void __auxio_sbus_set_lte(int on) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci __auxio_set_bit(AUXIO_AUX1_LTE, on, 0); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_civoid auxio_set_lte(int on) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci switch(auxio_devtype) { 8762306a36Sopenharmony_ci case AUXIO_TYPE_SBUS: 8862306a36Sopenharmony_ci __auxio_sbus_set_lte(on); 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci case AUXIO_TYPE_EBUS: 9162306a36Sopenharmony_ci default: 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL(auxio_set_lte); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const struct of_device_id auxio_match[] = { 9862306a36Sopenharmony_ci { 9962306a36Sopenharmony_ci .name = "auxio", 10062306a36Sopenharmony_ci }, 10162306a36Sopenharmony_ci {}, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, auxio_match); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int auxio_probe(struct platform_device *dev) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct device_node *dp = dev->dev.of_node; 10962306a36Sopenharmony_ci unsigned long size; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (of_node_name_eq(dp->parent, "ebus")) { 11262306a36Sopenharmony_ci auxio_devtype = AUXIO_TYPE_EBUS; 11362306a36Sopenharmony_ci size = sizeof(u32); 11462306a36Sopenharmony_ci } else if (of_node_name_eq(dp->parent, "sbus")) { 11562306a36Sopenharmony_ci auxio_devtype = AUXIO_TYPE_SBUS; 11662306a36Sopenharmony_ci size = 1; 11762306a36Sopenharmony_ci } else { 11862306a36Sopenharmony_ci printk("auxio: Unknown parent bus type [%pOFn]\n", 11962306a36Sopenharmony_ci dp->parent); 12062306a36Sopenharmony_ci return -ENODEV; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci auxio_register = of_ioremap(&dev->resource[0], 0, size, "auxio"); 12362306a36Sopenharmony_ci if (!auxio_register) 12462306a36Sopenharmony_ci return -ENODEV; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci printk(KERN_INFO "AUXIO: Found device at %pOF\n", dp); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (auxio_devtype == AUXIO_TYPE_EBUS) 12962306a36Sopenharmony_ci auxio_set_led(AUXIO_LED_ON); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic struct platform_driver auxio_driver = { 13562306a36Sopenharmony_ci .probe = auxio_probe, 13662306a36Sopenharmony_ci .driver = { 13762306a36Sopenharmony_ci .name = "auxio", 13862306a36Sopenharmony_ci .of_match_table = auxio_match, 13962306a36Sopenharmony_ci }, 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int __init auxio_init(void) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return platform_driver_register(&auxio_driver); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* Must be after subsys_initcall() so that busses are probed. Must 14862306a36Sopenharmony_ci * be before device_initcall() because things like the floppy driver 14962306a36Sopenharmony_ci * need to use the AUXIO register. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cifs_initcall(auxio_init); 152