Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 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_LICENSE("GPL v2");