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"); 123