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