brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · d6f9364 Raw
154 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>4 */5 6#include <linux/gpio/consumer.h>7#include <linux/module.h>8#include <linux/mod_devicetable.h>9#include <linux/platform_device.h>10 11#include <linux/delay.h>12 13#include "siox.h"14 15#define DRIVER_NAME "siox-gpio"16 17struct siox_gpio_ddata {18	struct gpio_desc *din;19	struct gpio_desc *dout;20	struct gpio_desc *dclk;21	struct gpio_desc *dld;22};23 24static unsigned int siox_clkhigh_ns = 1000;25static unsigned int siox_loadhigh_ns;26static unsigned int siox_bytegap_ns;27 28static int siox_gpio_pushpull(struct siox_master *smaster,29			      size_t setbuf_len, const u8 setbuf[],30			      size_t getbuf_len, u8 getbuf[])31{32	struct siox_gpio_ddata *ddata = siox_master_get_devdata(smaster);33	size_t i;34	size_t cycles = max(setbuf_len, getbuf_len);35 36	/* reset data and clock */37	gpiod_set_value_cansleep(ddata->dout, 0);38	gpiod_set_value_cansleep(ddata->dclk, 0);39 40	gpiod_set_value_cansleep(ddata->dld, 1);41	ndelay(siox_loadhigh_ns);42	gpiod_set_value_cansleep(ddata->dld, 0);43 44	for (i = 0; i < cycles; ++i) {45		u8 set = 0, get = 0;46		size_t j;47 48		if (i >= cycles - setbuf_len)49			set = setbuf[i - (cycles - setbuf_len)];50 51		for (j = 0; j < 8; ++j) {52			get <<= 1;53			if (gpiod_get_value_cansleep(ddata->din))54				get |= 1;55 56			/* DOUT is logically inverted */57			gpiod_set_value_cansleep(ddata->dout, !(set & 0x80));58			set <<= 1;59 60			gpiod_set_value_cansleep(ddata->dclk, 1);61			ndelay(siox_clkhigh_ns);62			gpiod_set_value_cansleep(ddata->dclk, 0);63		}64 65		if (i < getbuf_len)66			getbuf[i] = get;67 68		ndelay(siox_bytegap_ns);69	}70 71	gpiod_set_value_cansleep(ddata->dld, 1);72	ndelay(siox_loadhigh_ns);73	gpiod_set_value_cansleep(ddata->dld, 0);74 75	/*76	 * Resetting dout isn't necessary protocol wise, but it makes the77	 * signals more pretty because the dout level is deterministic between78	 * cycles. Note that this only affects dout between the master and the79	 * first siox device. dout for the later devices depend on the output of80	 * the previous siox device.81	 */82	gpiod_set_value_cansleep(ddata->dout, 0);83 84	return 0;85}86 87static int siox_gpio_probe(struct platform_device *pdev)88{89	struct device *dev = &pdev->dev;90	struct siox_gpio_ddata *ddata;91	int ret;92	struct siox_master *smaster;93 94	smaster = devm_siox_master_alloc(dev, sizeof(*ddata));95	if (!smaster)96		return dev_err_probe(dev, -ENOMEM,97				     "failed to allocate siox master\n");98 99	platform_set_drvdata(pdev, smaster);100	ddata = siox_master_get_devdata(smaster);101 102	ddata->din = devm_gpiod_get(dev, "din", GPIOD_IN);103	if (IS_ERR(ddata->din))104		return dev_err_probe(dev, PTR_ERR(ddata->din),105				     "Failed to get din GPIO\n");106 107	ddata->dout = devm_gpiod_get(dev, "dout", GPIOD_OUT_LOW);108	if (IS_ERR(ddata->dout))109		return dev_err_probe(dev, PTR_ERR(ddata->dout),110				     "Failed to get dout GPIO\n");111 112	ddata->dclk = devm_gpiod_get(dev, "dclk", GPIOD_OUT_LOW);113	if (IS_ERR(ddata->dclk))114		return dev_err_probe(dev, PTR_ERR(ddata->dclk),115				     "Failed to get dclk GPIO\n");116 117	ddata->dld = devm_gpiod_get(dev, "dld", GPIOD_OUT_LOW);118	if (IS_ERR(ddata->dld))119		return dev_err_probe(dev, PTR_ERR(ddata->dld),120				     "Failed to get dld GPIO\n");121 122	smaster->pushpull = siox_gpio_pushpull;123	/* XXX: determine automatically like spi does */124	smaster->busno = 0;125 126	ret = devm_siox_master_register(dev, smaster);127	if (ret)128		return dev_err_probe(dev, ret,129				     "Failed to register siox master\n");130 131	return 0;132}133 134static const struct of_device_id siox_gpio_dt_ids[] = {135	{ .compatible = "eckelmann,siox-gpio", },136	{ /* sentinel */ }137};138MODULE_DEVICE_TABLE(of, siox_gpio_dt_ids);139 140static struct platform_driver siox_gpio_driver = {141	.probe = siox_gpio_probe,142 143	.driver = {144		.name = DRIVER_NAME,145		.of_match_table = siox_gpio_dt_ids,146	},147};148module_platform_driver(siox_gpio_driver);149 150MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");151MODULE_DESCRIPTION("SIOX GPIO bus driver");152MODULE_LICENSE("GPL v2");153MODULE_ALIAS("platform:" DRIVER_NAME);154