0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <linux/err.h>
0029 #include <linux/module.h>
0030 #include <linux/gpio/driver.h>
0031 #include <linux/bitops.h>
0032 #include <linux/platform_device.h>
0033
0034 #include <asm/coprocessor.h> /* CPENABLE read/write macros */
0035
0036 #ifndef XCHAL_CP_ID_XTIOP
0037 #error GPIO32 option is not enabled for your xtensa core variant
0038 #endif
0039
0040 #if XCHAL_HAVE_CP
0041
0042 static inline unsigned long enable_cp(unsigned long *cpenable)
0043 {
0044 unsigned long flags;
0045
0046 local_irq_save(flags);
0047 *cpenable = xtensa_get_sr(cpenable);
0048 xtensa_set_sr(*cpenable | BIT(XCHAL_CP_ID_XTIOP), cpenable);
0049 return flags;
0050 }
0051
0052 static inline void disable_cp(unsigned long flags, unsigned long cpenable)
0053 {
0054 xtensa_set_sr(cpenable, cpenable);
0055 local_irq_restore(flags);
0056 }
0057
0058 #else
0059
0060 static inline unsigned long enable_cp(unsigned long *cpenable)
0061 {
0062 *cpenable = 0;
0063 return 0;
0064 }
0065
0066 static inline void disable_cp(unsigned long flags, unsigned long cpenable)
0067 {
0068 }
0069
0070 #endif
0071
0072 static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset)
0073 {
0074 return GPIO_LINE_DIRECTION_IN;
0075 }
0076
0077 static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset)
0078 {
0079 unsigned long flags, saved_cpenable;
0080 u32 impwire;
0081
0082 flags = enable_cp(&saved_cpenable);
0083 __asm__ __volatile__("read_impwire %0" : "=a" (impwire));
0084 disable_cp(flags, saved_cpenable);
0085
0086 return !!(impwire & BIT(offset));
0087 }
0088
0089 static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset,
0090 int value)
0091 {
0092 BUG();
0093 }
0094
0095 static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset)
0096 {
0097 return GPIO_LINE_DIRECTION_OUT;
0098 }
0099
0100 static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset)
0101 {
0102 unsigned long flags, saved_cpenable;
0103 u32 expstate;
0104
0105 flags = enable_cp(&saved_cpenable);
0106 __asm__ __volatile__("rur.expstate %0" : "=a" (expstate));
0107 disable_cp(flags, saved_cpenable);
0108
0109 return !!(expstate & BIT(offset));
0110 }
0111
0112 static void xtensa_expstate_set_value(struct gpio_chip *gc, unsigned offset,
0113 int value)
0114 {
0115 unsigned long flags, saved_cpenable;
0116 u32 mask = BIT(offset);
0117 u32 val = value ? BIT(offset) : 0;
0118
0119 flags = enable_cp(&saved_cpenable);
0120 __asm__ __volatile__("wrmsk_expstate %0, %1"
0121 :: "a" (val), "a" (mask));
0122 disable_cp(flags, saved_cpenable);
0123 }
0124
0125 static struct gpio_chip impwire_chip = {
0126 .label = "impwire",
0127 .base = -1,
0128 .ngpio = 32,
0129 .get_direction = xtensa_impwire_get_direction,
0130 .get = xtensa_impwire_get_value,
0131 .set = xtensa_impwire_set_value,
0132 };
0133
0134 static struct gpio_chip expstate_chip = {
0135 .label = "expstate",
0136 .base = -1,
0137 .ngpio = 32,
0138 .get_direction = xtensa_expstate_get_direction,
0139 .get = xtensa_expstate_get_value,
0140 .set = xtensa_expstate_set_value,
0141 };
0142
0143 static int xtensa_gpio_probe(struct platform_device *pdev)
0144 {
0145 int ret;
0146
0147 ret = gpiochip_add_data(&impwire_chip, NULL);
0148 if (ret)
0149 return ret;
0150 return gpiochip_add_data(&expstate_chip, NULL);
0151 }
0152
0153 static struct platform_driver xtensa_gpio_driver = {
0154 .driver = {
0155 .name = "xtensa-gpio",
0156 },
0157 .probe = xtensa_gpio_probe,
0158 };
0159
0160 static int __init xtensa_gpio_init(void)
0161 {
0162 struct platform_device *pdev;
0163
0164 pdev = platform_device_register_simple("xtensa-gpio", 0, NULL, 0);
0165 if (IS_ERR(pdev))
0166 return PTR_ERR(pdev);
0167
0168 return platform_driver_register(&xtensa_gpio_driver);
0169 }
0170 device_initcall(xtensa_gpio_init);
0171
0172 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
0173 MODULE_DESCRIPTION("Xtensa LX4 GPIO32 driver");
0174 MODULE_LICENSE("GPL");