Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * MAX1600 PCMCIA power switch library
0004  *
0005  * Copyright (C) 2016 Russell King
0006  */
0007 #include <linux/device.h>
0008 #include <linux/module.h>
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/slab.h>
0011 #include "max1600.h"
0012 
0013 static const char *max1600_gpio_name[2][MAX1600_GPIO_MAX] = {
0014     { "a0vcc", "a1vcc", "a0vpp", "a1vpp" },
0015     { "b0vcc", "b1vcc", "b0vpp", "b1vpp" },
0016 };
0017 
0018 int max1600_init(struct device *dev, struct max1600 **ptr,
0019     unsigned int channel, unsigned int code)
0020 {
0021     struct max1600 *m;
0022     int chan;
0023     int i;
0024 
0025     switch (channel) {
0026     case MAX1600_CHAN_A:
0027         chan = 0;
0028         break;
0029     case MAX1600_CHAN_B:
0030         chan = 1;
0031         break;
0032     default:
0033         return -EINVAL;
0034     }
0035 
0036     if (code != MAX1600_CODE_LOW && code != MAX1600_CODE_HIGH)
0037         return -EINVAL;
0038 
0039     m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL);
0040     if (!m)
0041         return -ENOMEM;
0042 
0043     m->dev = dev;
0044     m->code = code;
0045 
0046     for (i = 0; i < MAX1600_GPIO_MAX; i++) {
0047         const char *name;
0048 
0049         name = max1600_gpio_name[chan][i];
0050         if (i != MAX1600_GPIO_0VPP) {
0051             m->gpio[i] = devm_gpiod_get(dev, name, GPIOD_OUT_LOW);
0052         } else {
0053             m->gpio[i] = devm_gpiod_get_optional(dev, name,
0054                                  GPIOD_OUT_LOW);
0055             if (!m->gpio[i])
0056                 break;
0057         }
0058         if (IS_ERR(m->gpio[i]))
0059             return PTR_ERR(m->gpio[i]);
0060     }
0061 
0062     *ptr = m;
0063 
0064     return 0;
0065 }
0066 EXPORT_SYMBOL_GPL(max1600_init);
0067 
0068 int max1600_configure(struct max1600 *m, unsigned int vcc, unsigned int vpp)
0069 {
0070     DECLARE_BITMAP(values, MAX1600_GPIO_MAX) = { 0, };
0071     int n = MAX1600_GPIO_0VPP;
0072 
0073     if (m->gpio[MAX1600_GPIO_0VPP]) {
0074         if (vpp == 0) {
0075             __assign_bit(MAX1600_GPIO_0VPP, values, 0);
0076             __assign_bit(MAX1600_GPIO_1VPP, values, 0);
0077         } else if (vpp == 120) {
0078             __assign_bit(MAX1600_GPIO_0VPP, values, 0);
0079             __assign_bit(MAX1600_GPIO_1VPP, values, 1);
0080         } else if (vpp == vcc) {
0081             __assign_bit(MAX1600_GPIO_0VPP, values, 1);
0082             __assign_bit(MAX1600_GPIO_1VPP, values, 0);
0083         } else {
0084             dev_err(m->dev, "unrecognised Vpp %u.%uV\n",
0085                 vpp / 10, vpp % 10);
0086             return -EINVAL;
0087         }
0088         n = MAX1600_GPIO_MAX;
0089     } else if (vpp != vcc && vpp != 0) {
0090         dev_err(m->dev, "no VPP control\n");
0091         return -EINVAL;
0092     }
0093 
0094     if (vcc == 0) {
0095         __assign_bit(MAX1600_GPIO_0VCC, values, 0);
0096         __assign_bit(MAX1600_GPIO_1VCC, values, 0);
0097     } else if (vcc == 33) { /* VY */
0098         __assign_bit(MAX1600_GPIO_0VCC, values, 1);
0099         __assign_bit(MAX1600_GPIO_1VCC, values, 0);
0100     } else if (vcc == 50) { /* VX */
0101         __assign_bit(MAX1600_GPIO_0VCC, values, 0);
0102         __assign_bit(MAX1600_GPIO_1VCC, values, 1);
0103     } else {
0104         dev_err(m->dev, "unrecognised Vcc %u.%uV\n",
0105             vcc / 10, vcc % 10);
0106         return -EINVAL;
0107     }
0108 
0109     if (m->code == MAX1600_CODE_HIGH) {
0110         /*
0111          * Cirrus mode appears to be the same as Intel mode,
0112          * except the VCC pins are inverted.
0113          */
0114         __change_bit(MAX1600_GPIO_0VCC, values);
0115         __change_bit(MAX1600_GPIO_1VCC, values);
0116     }
0117 
0118     return gpiod_set_array_value_cansleep(n, m->gpio, NULL, values);
0119 }
0120 EXPORT_SYMBOL_GPL(max1600_configure);
0121 
0122 MODULE_LICENSE("GPL v2");