Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pcmcia: add MAX1600 library

Add a library for the MAX1600 PCMCIA power switch device. This is a
dual-channel device, controlled via four GPIO signals per channel.
Two signals control the Vcc output, and two control the Vpp output.

Acked-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

+158
+3
drivers/pcmcia/Kconfig
··· 63 63 64 64 If unsure, say Y. 65 65 66 + config PCMCIA_MAX1600 67 + tristate 68 + 66 69 comment "PC-card bridges" 67 70 68 71 config YENTA
+1
drivers/pcmcia/Makefile
··· 35 35 obj-$(CONFIG_AT91_CF) += at91_cf.o 36 36 obj-$(CONFIG_ELECTRA_CF) += electra_cf.o 37 37 obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o 38 + obj-$(CONFIG_PCMCIA_MAX1600) += max1600.o 38 39 39 40 sa1111_cs-y += sa1111_generic.o 40 41 sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o
+122
drivers/pcmcia/max1600.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * MAX1600 PCMCIA power switch library 4 + * 5 + * Copyright (C) 2016 Russell King 6 + */ 7 + #include <linux/device.h> 8 + #include <linux/module.h> 9 + #include <linux/gpio/consumer.h> 10 + #include <linux/slab.h> 11 + #include "max1600.h" 12 + 13 + static const char *max1600_gpio_name[2][MAX1600_GPIO_MAX] = { 14 + { "a0vcc", "a1vcc", "a0vpp", "a1vpp" }, 15 + { "b0vcc", "b1vcc", "b0vpp", "b1vpp" }, 16 + }; 17 + 18 + int max1600_init(struct device *dev, struct max1600 **ptr, 19 + unsigned int channel, unsigned int code) 20 + { 21 + struct max1600 *m; 22 + int chan; 23 + int i; 24 + 25 + switch (channel) { 26 + case MAX1600_CHAN_A: 27 + chan = 0; 28 + break; 29 + case MAX1600_CHAN_B: 30 + chan = 1; 31 + break; 32 + default: 33 + return -EINVAL; 34 + } 35 + 36 + if (code != MAX1600_CODE_LOW && code != MAX1600_CODE_HIGH) 37 + return -EINVAL; 38 + 39 + m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL); 40 + if (!m) 41 + return -ENOMEM; 42 + 43 + m->dev = dev; 44 + m->code = code; 45 + 46 + for (i = 0; i < MAX1600_GPIO_MAX; i++) { 47 + const char *name; 48 + 49 + name = max1600_gpio_name[chan][i]; 50 + if (i != MAX1600_GPIO_0VPP) { 51 + m->gpio[i] = devm_gpiod_get(dev, name, GPIOD_OUT_LOW); 52 + } else { 53 + m->gpio[i] = devm_gpiod_get_optional(dev, name, 54 + GPIOD_OUT_LOW); 55 + if (!m->gpio[i]) 56 + break; 57 + } 58 + if (IS_ERR(m->gpio[i])) 59 + return PTR_ERR(m->gpio[i]); 60 + } 61 + 62 + *ptr = m; 63 + 64 + return 0; 65 + } 66 + EXPORT_SYMBOL_GPL(max1600_init); 67 + 68 + int max1600_configure(struct max1600 *m, unsigned int vcc, unsigned int vpp) 69 + { 70 + DECLARE_BITMAP(values, MAX1600_GPIO_MAX) = { 0, }; 71 + int n = MAX1600_GPIO_0VPP; 72 + 73 + if (m->gpio[MAX1600_GPIO_0VPP]) { 74 + if (vpp == 0) { 75 + __assign_bit(MAX1600_GPIO_0VPP, values, 0); 76 + __assign_bit(MAX1600_GPIO_1VPP, values, 0); 77 + } else if (vpp == 120) { 78 + __assign_bit(MAX1600_GPIO_0VPP, values, 0); 79 + __assign_bit(MAX1600_GPIO_1VPP, values, 1); 80 + } else if (vpp == vcc) { 81 + __assign_bit(MAX1600_GPIO_0VPP, values, 1); 82 + __assign_bit(MAX1600_GPIO_1VPP, values, 0); 83 + } else { 84 + dev_err(m->dev, "unrecognised Vpp %u.%uV\n", 85 + vpp / 10, vpp % 10); 86 + return -EINVAL; 87 + } 88 + n = MAX1600_GPIO_MAX; 89 + } else if (vpp != vcc && vpp != 0) { 90 + dev_err(m->dev, "no VPP control\n"); 91 + return -EINVAL; 92 + } 93 + 94 + if (vcc == 0) { 95 + __assign_bit(MAX1600_GPIO_0VCC, values, 0); 96 + __assign_bit(MAX1600_GPIO_1VCC, values, 0); 97 + } else if (vcc == 33) { /* VY */ 98 + __assign_bit(MAX1600_GPIO_0VCC, values, 1); 99 + __assign_bit(MAX1600_GPIO_1VCC, values, 0); 100 + } else if (vcc == 50) { /* VX */ 101 + __assign_bit(MAX1600_GPIO_0VCC, values, 0); 102 + __assign_bit(MAX1600_GPIO_1VCC, values, 1); 103 + } else { 104 + dev_err(m->dev, "unrecognised Vcc %u.%uV\n", 105 + vcc / 10, vcc % 10); 106 + return -EINVAL; 107 + } 108 + 109 + if (m->code == MAX1600_CODE_HIGH) { 110 + /* 111 + * Cirrus mode appears to be the same as Intel mode, 112 + * except the VCC pins are inverted. 113 + */ 114 + __change_bit(MAX1600_GPIO_0VCC, values); 115 + __change_bit(MAX1600_GPIO_1VCC, values); 116 + } 117 + 118 + return gpiod_set_array_value_cansleep(n, m->gpio, NULL, values); 119 + } 120 + EXPORT_SYMBOL_GPL(max1600_configure); 121 + 122 + MODULE_LICENSE("GPL v2");
+32
drivers/pcmcia/max1600.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef MAX1600_H 3 + #define MAX1600_H 4 + 5 + struct gpio_desc; 6 + 7 + enum { 8 + MAX1600_GPIO_0VCC = 0, 9 + MAX1600_GPIO_1VCC, 10 + MAX1600_GPIO_0VPP, 11 + MAX1600_GPIO_1VPP, 12 + MAX1600_GPIO_MAX, 13 + 14 + MAX1600_CHAN_A, 15 + MAX1600_CHAN_B, 16 + 17 + MAX1600_CODE_LOW, 18 + MAX1600_CODE_HIGH, 19 + }; 20 + 21 + struct max1600 { 22 + struct gpio_desc *gpio[MAX1600_GPIO_MAX]; 23 + struct device *dev; 24 + unsigned int code; 25 + }; 26 + 27 + int max1600_init(struct device *dev, struct max1600 **ptr, 28 + unsigned int channel, unsigned int code); 29 + 30 + int max1600_configure(struct max1600 *, unsigned int vcc, unsigned int vpp); 31 + 32 + #endif