cregit-Linux how code gets into the kernel

Release 4.7 drivers/gpio/gpio-xtensa.c

Directory: drivers/gpio
/*
 * Copyright (C) 2013 TangoTec Ltd.
 * Author: Baruch Siach <baruch@tkos.co.il>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Driver for the Xtensa LX4 GPIO32 Option
 *
 * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22
 *
 * GPIO32 is a standard optional extension to the Xtensa architecture core that
 * provides preconfigured output and input ports for intra SoC signaling. The
 * GPIO32 option is implemented as 32bit Tensilica Instruction Extension (TIE)
 * output state called EXPSTATE, and 32bit input wire called IMPWIRE. This
 * driver treats input and output states as two distinct devices.
 *
 * Access to GPIO32 specific instructions is controlled by the CPENABLE
 * (Coprocessor Enable Bits) register. By default Xtensa Linux startup code
 * disables access to all coprocessors. This driver sets the CPENABLE bit
 * corresponding to GPIO32 before any GPIO32 specific instruction, and restores
 * CPENABLE state after that.
 *
 * This driver is currently incompatible with SMP. The GPIO32 extension is not
 * guaranteed to be available in all cores. Moreover, each core controls a
 * different set of IO wires. A theoretical SMP aware version of this driver
 * would need to have a per core workqueue to do the actual GPIO manipulation.
 */

#include <linux/err.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>

#include <asm/coprocessor.h> /* CPENABLE read/write macros */

#ifndef XCHAL_CP_ID_XTIOP
#error GPIO32 option is not enabled for your xtensa core variant
#endif

#if XCHAL_HAVE_CP


static inline unsigned long enable_cp(unsigned long *cpenable) { unsigned long flags; local_irq_save(flags); RSR_CPENABLE(*cpenable); WSR_CPENABLE(*cpenable | BIT(XCHAL_CP_ID_XTIOP)); return flags; }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach42100.00%1100.00%
Total42100.00%1100.00%


static inline void disable_cp(unsigned long flags, unsigned long cpenable) { WSR_CPENABLE(cpenable); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach25100.00%1100.00%
Total25100.00%1100.00%

#else
static inline unsigned long enable_cp(unsigned long *cpenable) { *cpenable = 0; /* avoid uninitialized value warning */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach22100.00%1100.00%
Total22100.00%1100.00%


static inline void disable_cp(unsigned long flags, unsigned long cpenable) { }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach14100.00%1100.00%
Total14100.00%1100.00%

#endif /* XCHAL_HAVE_CP */
static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) { return 1; /* input only */ }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach18100.00%1100.00%
Total18100.00%1100.00%


static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset) { unsigned long flags, saved_cpenable; u32 impwire; flags = enable_cp(&saved_cpenable); __asm__ __volatile__("read_impwire %0" : "=a" (impwire)); disable_cp(flags, saved_cpenable); return !!(impwire & BIT(offset)); }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach53100.00%1100.00%
Total53100.00%1100.00%


static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset, int value) { BUG(); /* output only; should never be called */ }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach21100.00%1100.00%
Total21100.00%1100.00%


static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset) { return 0; /* output only */ }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach18100.00%1100.00%
Total18100.00%1100.00%


static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset) { unsigned long flags, saved_cpenable; u32 expstate; flags = enable_cp(&saved_cpenable); __asm__ __volatile__("rur.expstate %0" : "=a" (expstate)); disable_cp(flags, saved_cpenable); return !!(expstate & BIT(offset)); }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach53100.00%1100.00%
Total53100.00%1100.00%


static void xtensa_expstate_set_value(struct gpio_chip *gc, unsigned offset, int value) { unsigned long flags, saved_cpenable; u32 mask = BIT(offset); u32 val = value ? BIT(offset) : 0; flags = enable_cp(&saved_cpenable); __asm__ __volatile__("wrmsk_expstate %0, %1" :: "a" (val), "a" (mask)); disable_cp(flags, saved_cpenable); }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach61100.00%1100.00%
Total61100.00%1100.00%

static struct gpio_chip impwire_chip = { .label = "impwire", .base = -1, .ngpio = 32, .get_direction = xtensa_impwire_get_direction, .get = xtensa_impwire_get_value, .set = xtensa_impwire_set_value, }; static struct gpio_chip expstate_chip = { .label = "expstate", .base = -1, .ngpio = 32, .get_direction = xtensa_expstate_get_direction, .get = xtensa_expstate_get_value, .set = xtensa_expstate_set_value, };
static int xtensa_gpio_probe(struct platform_device *pdev) { int ret; ret = gpiochip_add_data(&impwire_chip, NULL); if (ret) return ret; return gpiochip_add_data(&expstate_chip, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach3485.00%150.00%
linus walleijlinus walleij615.00%150.00%
Total40100.00%2100.00%

static struct platform_driver xtensa_gpio_driver = { .driver = { .name = "xtensa-gpio", }, .probe = xtensa_gpio_probe, };
static int __init xtensa_gpio_init(void) { struct platform_device *pdev; pdev = platform_device_register_simple("xtensa-gpio", 0, NULL, 0); if (IS_ERR(pdev)) return PTR_ERR(pdev); return platform_driver_register(&xtensa_gpio_driver); }

Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach47100.00%1100.00%
Total47100.00%1100.00%

device_initcall(xtensa_gpio_init); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); MODULE_DESCRIPTION("Xtensa LX4 GPIO32 driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
baruch siachbaruch siach56298.94%266.67%
linus walleijlinus walleij61.06%133.33%
Total568100.00%3100.00%
Directory: drivers/gpio
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}