brintos

brintos / linux-shallow public Read only

0
0
Text · 2.9 KiB · 7be9068 Raw
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