124 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * MAX1600 PCMCIA power switch library4 *5 * Copyright (C) 2016 Russell King6 */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 13static const char *max1600_gpio_name[2][MAX1600_GPIO_MAX] = {14 { "a0vcc", "a1vcc", "a0vpp", "a1vpp" },15 { "b0vcc", "b1vcc", "b0vpp", "b1vpp" },16};17 18int 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}66EXPORT_SYMBOL_GPL(max1600_init);67 68int 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}120EXPORT_SYMBOL_GPL(max1600_configure);121 122MODULE_DESCRIPTION("MAX1600 PCMCIA power switch library");123MODULE_LICENSE("GPL v2");124