0001
0002
0003
0004
0005
0006
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/mutex.h>
0012 #include <linux/gpio/driver.h>
0013 #include <linux/of.h>
0014 #include <linux/of_gpio.h>
0015 #include <linux/io.h>
0016 #include <linux/slab.h>
0017
0018 #include <lantiq_soc.h>
0019
0020
0021
0022
0023
0024
0025
0026 #define LTQ_EBU_BUSCON 0x1e7ff
0027 #define LTQ_EBU_WP 0x80000000
0028
0029 struct ltq_mm {
0030 struct of_mm_gpio_chip mmchip;
0031 u16 shadow;
0032 };
0033
0034
0035
0036
0037
0038
0039
0040
0041 static void ltq_mm_apply(struct ltq_mm *chip)
0042 {
0043 unsigned long flags;
0044
0045 spin_lock_irqsave(&ebu_lock, flags);
0046 ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1);
0047 __raw_writew(chip->shadow, chip->mmchip.regs);
0048 ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
0049 spin_unlock_irqrestore(&ebu_lock, flags);
0050 }
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 static void ltq_mm_set(struct gpio_chip *gc, unsigned offset, int value)
0061 {
0062 struct ltq_mm *chip = gpiochip_get_data(gc);
0063
0064 if (value)
0065 chip->shadow |= (1 << offset);
0066 else
0067 chip->shadow &= ~(1 << offset);
0068 ltq_mm_apply(chip);
0069 }
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 static int ltq_mm_dir_out(struct gpio_chip *gc, unsigned offset, int value)
0080 {
0081 ltq_mm_set(gc, offset, value);
0082
0083 return 0;
0084 }
0085
0086
0087
0088
0089
0090 static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc)
0091 {
0092 struct ltq_mm *chip =
0093 container_of(mm_gc, struct ltq_mm, mmchip);
0094
0095
0096 ltq_ebu_w32(CPHYSADDR(chip->mmchip.regs) | 0x1, LTQ_EBU_ADDRSEL1);
0097
0098 ltq_mm_apply(chip);
0099 }
0100
0101 static int ltq_mm_probe(struct platform_device *pdev)
0102 {
0103 struct ltq_mm *chip;
0104 u32 shadow;
0105
0106 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
0107 if (!chip)
0108 return -ENOMEM;
0109
0110 platform_set_drvdata(pdev, chip);
0111
0112 chip->mmchip.gc.ngpio = 16;
0113 chip->mmchip.gc.direction_output = ltq_mm_dir_out;
0114 chip->mmchip.gc.set = ltq_mm_set;
0115 chip->mmchip.save_regs = ltq_mm_save_regs;
0116
0117
0118 if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
0119 chip->shadow = shadow;
0120
0121 return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip);
0122 }
0123
0124 static int ltq_mm_remove(struct platform_device *pdev)
0125 {
0126 struct ltq_mm *chip = platform_get_drvdata(pdev);
0127
0128 of_mm_gpiochip_remove(&chip->mmchip);
0129
0130 return 0;
0131 }
0132
0133 static const struct of_device_id ltq_mm_match[] = {
0134 { .compatible = "lantiq,gpio-mm" },
0135 {},
0136 };
0137 MODULE_DEVICE_TABLE(of, ltq_mm_match);
0138
0139 static struct platform_driver ltq_mm_driver = {
0140 .probe = ltq_mm_probe,
0141 .remove = ltq_mm_remove,
0142 .driver = {
0143 .name = "gpio-mm-ltq",
0144 .of_match_table = ltq_mm_match,
0145 },
0146 };
0147
0148 static int __init ltq_mm_init(void)
0149 {
0150 return platform_driver_register(<q_mm_driver);
0151 }
0152
0153 subsys_initcall(ltq_mm_init);
0154
0155 static void __exit ltq_mm_exit(void)
0156 {
0157 platform_driver_unregister(<q_mm_driver);
0158 }
0159 module_exit(ltq_mm_exit);