brintos

brintos / linux-shallow public Read only

0
0
Text · 14.4 KiB · 6946a65 Raw
524 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * IIO driver for the Apex Embedded Systems STX1044 * Copyright (C) 2016 William Breathitt Gray5 */6#include <linux/bitfield.h>7#include <linux/bits.h>8#include <linux/device.h>9#include <linux/err.h>10#include <linux/gpio/regmap.h>11#include <linux/i8254.h>12#include <linux/iio/iio.h>13#include <linux/iio/types.h>14#include <linux/isa.h>15#include <linux/kernel.h>16#include <linux/limits.h>17#include <linux/module.h>18#include <linux/moduleparam.h>19#include <linux/mutex.h>20#include <linux/regmap.h>21#include <linux/types.h>22 23#define STX104_OUT_CHAN(chan) {				\24	.type = IIO_VOLTAGE,				\25	.channel = chan,				\26	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\27	.indexed = 1,					\28	.output = 1					\29}30#define STX104_IN_CHAN(chan, diff) {					\31	.type = IIO_VOLTAGE,						\32	.channel = chan,						\33	.channel2 = chan,						\34	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) |	\35		BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),	\36	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\37	.indexed = 1,							\38	.differential = diff						\39}40 41#define STX104_NUM_OUT_CHAN 242 43#define STX104_EXTENT 1644 45static unsigned int base[max_num_isa_dev(STX104_EXTENT)];46static unsigned int num_stx104;47module_param_hw_array(base, uint, ioport, &num_stx104, 0);48MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");49 50#define STX104_AIO_BASE 0x051#define STX104_SOFTWARE_STROBE STX104_AIO_BASE52#define STX104_ADC_DATA STX104_AIO_BASE53#define STX104_ADC_CHANNEL (STX104_AIO_BASE + 0x2)54#define STX104_DIO_REG (STX104_AIO_BASE + 0x3)55#define STX104_DAC_BASE (STX104_AIO_BASE + 0x4)56#define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8)57#define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9)58#define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11)59#define STX104_I8254_BASE (STX104_AIO_BASE + 0x12)60 61#define STX104_AIO_DATA_STRIDE 262#define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel))63 64/* ADC Channel */65#define STX104_FC GENMASK(3, 0)66#define STX104_LC GENMASK(7, 4)67#define STX104_SINGLE_CHANNEL(_channel) \68	(u8_encode_bits(_channel, STX104_FC) | u8_encode_bits(_channel, STX104_LC))69 70/* ADC Status */71#define STX104_SD BIT(5)72#define STX104_CNV BIT(7)73#define STX104_DIFFERENTIAL 174 75/* ADC Control */76#define STX104_ALSS GENMASK(1, 0)77#define STX104_SOFTWARE_TRIGGER u8_encode_bits(0x0, STX104_ALSS)78 79/* ADC Configuration */80#define STX104_GAIN GENMASK(1, 0)81#define STX104_ADBU BIT(2)82#define STX104_RBK GENMASK(7, 4)83#define STX104_BIPOLAR 084#define STX104_GAIN_X1 085#define STX104_GAIN_X2 186#define STX104_GAIN_X4 287#define STX104_GAIN_X8 388 89/**90 * struct stx104_iio - IIO device private data structure91 * @lock: synchronization lock to prevent I/O race conditions92 * @aio_data_map: Regmap for analog I/O data93 * @aio_ctl_map: Regmap for analog I/O control94 */95struct stx104_iio {96	struct mutex lock;97	struct regmap *aio_data_map;98	struct regmap *aio_ctl_map;99};100 101static const struct regmap_range aio_ctl_wr_ranges[] = {102	regmap_reg_range(0x0, 0x0), regmap_reg_range(0x2, 0x2), regmap_reg_range(0x9, 0x9),103	regmap_reg_range(0x11, 0x11),104};105static const struct regmap_range aio_ctl_rd_ranges[] = {106	regmap_reg_range(0x2, 0x2), regmap_reg_range(0x8, 0x9), regmap_reg_range(0x11, 0x11),107};108static const struct regmap_range aio_ctl_volatile_ranges[] = {109	regmap_reg_range(0x8, 0x8),110};111static const struct regmap_access_table aio_ctl_wr_table = {112	.yes_ranges = aio_ctl_wr_ranges,113	.n_yes_ranges = ARRAY_SIZE(aio_ctl_wr_ranges),114};115static const struct regmap_access_table aio_ctl_rd_table = {116	.yes_ranges = aio_ctl_rd_ranges,117	.n_yes_ranges = ARRAY_SIZE(aio_ctl_rd_ranges),118};119static const struct regmap_access_table aio_ctl_volatile_table = {120	.yes_ranges = aio_ctl_volatile_ranges,121	.n_yes_ranges = ARRAY_SIZE(aio_ctl_volatile_ranges),122};123 124static const struct regmap_config aio_ctl_regmap_config = {125	.name = "aio_ctl",126	.reg_bits = 8,127	.reg_stride = 1,128	.reg_base = STX104_AIO_BASE,129	.val_bits = 8,130	.io_port = true,131	.wr_table = &aio_ctl_wr_table,132	.rd_table = &aio_ctl_rd_table,133	.volatile_table = &aio_ctl_volatile_table,134	.cache_type = REGCACHE_FLAT,135};136 137static const struct regmap_range aio_data_wr_ranges[] = {138	regmap_reg_range(0x4, 0x6),139};140static const struct regmap_range aio_data_rd_ranges[] = {141	regmap_reg_range(0x0, 0x0),142};143static const struct regmap_access_table aio_data_wr_table = {144	.yes_ranges = aio_data_wr_ranges,145	.n_yes_ranges = ARRAY_SIZE(aio_data_wr_ranges),146};147static const struct regmap_access_table aio_data_rd_table = {148	.yes_ranges = aio_data_rd_ranges,149	.n_yes_ranges = ARRAY_SIZE(aio_data_rd_ranges),150};151 152static const struct regmap_config aio_data_regmap_config = {153	.name = "aio_data",154	.reg_bits = 16,155	.reg_stride = STX104_AIO_DATA_STRIDE,156	.reg_base = STX104_AIO_BASE,157	.val_bits = 16,158	.io_port = true,159	.wr_table = &aio_data_wr_table,160	.rd_table = &aio_data_rd_table,161	.volatile_table = &aio_data_rd_table,162	.cache_type = REGCACHE_FLAT,163};164 165static const struct regmap_config dio_regmap_config = {166	.name = "dio",167	.reg_bits = 8,168	.reg_stride = 1,169	.reg_base = STX104_DIO_REG,170	.val_bits = 8,171	.io_port = true,172};173 174static const struct regmap_range pit_wr_ranges[] = {175	regmap_reg_range(0x0, 0x3),176};177static const struct regmap_range pit_rd_ranges[] = {178	regmap_reg_range(0x0, 0x2),179};180static const struct regmap_access_table pit_wr_table = {181	.yes_ranges = pit_wr_ranges,182	.n_yes_ranges = ARRAY_SIZE(pit_wr_ranges),183};184static const struct regmap_access_table pit_rd_table = {185	.yes_ranges = pit_rd_ranges,186	.n_yes_ranges = ARRAY_SIZE(pit_rd_ranges),187};188 189static const struct regmap_config pit_regmap_config = {190	.name = "i8254",191	.reg_bits = 8,192	.reg_stride = 1,193	.reg_base = STX104_I8254_BASE,194	.val_bits = 8,195	.io_port = true,196	.wr_table = &pit_wr_table,197	.rd_table = &pit_rd_table,198};199 200static int stx104_read_raw(struct iio_dev *indio_dev,201	struct iio_chan_spec const *chan, int *val, int *val2, long mask)202{203	struct stx104_iio *const priv = iio_priv(indio_dev);204	int err;205	unsigned int adc_config;206	unsigned int value;207	unsigned int adc_status;208 209	switch (mask) {210	case IIO_CHAN_INFO_HARDWAREGAIN:211		err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);212		if (err)213			return err;214 215		*val = BIT(u8_get_bits(adc_config, STX104_GAIN));216		return IIO_VAL_INT;217	case IIO_CHAN_INFO_RAW:218		if (chan->output) {219			err = regmap_read(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel),220					  &value);221			if (err)222				return err;223			*val = value;224			return IIO_VAL_INT;225		}226 227		mutex_lock(&priv->lock);228 229		/* select ADC channel */230		err = regmap_write(priv->aio_ctl_map, STX104_ADC_CHANNEL,231				   STX104_SINGLE_CHANNEL(chan->channel));232		if (err) {233			mutex_unlock(&priv->lock);234			return err;235		}236 237		/*238		 * Trigger ADC sample capture by writing to the 8-bit Software Strobe Register and239		 * wait for completion; the conversion time range is 5 microseconds to 53.68 seconds240		 * in steps of 25 nanoseconds. The actual Analog Input Frame Timer time interval is241		 * calculated as:242		 * ai_time_frame_ns = ( AIFT + 1 ) * ( 25 nanoseconds ).243		 * Where 0 <= AIFT <= 2147483648.244		 */245		err = regmap_write(priv->aio_ctl_map, STX104_SOFTWARE_STROBE, 0);246		if (err) {247			mutex_unlock(&priv->lock);248			return err;249		}250		err = regmap_read_poll_timeout(priv->aio_ctl_map, STX104_ADC_STATUS, adc_status,251					       !u8_get_bits(adc_status, STX104_CNV), 0, 53687092);252		if (err) {253			mutex_unlock(&priv->lock);254			return err;255		}256 257		err = regmap_read(priv->aio_data_map, STX104_ADC_DATA, &value);258		if (err) {259			mutex_unlock(&priv->lock);260			return err;261		}262		*val = value;263 264		mutex_unlock(&priv->lock);265		return IIO_VAL_INT;266	case IIO_CHAN_INFO_OFFSET:267		/* get ADC bipolar/unipolar configuration */268		err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);269		if (err)270			return err;271 272		*val = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? -32768 : 0;273		return IIO_VAL_INT;274	case IIO_CHAN_INFO_SCALE:275		/* get ADC bipolar/unipolar and gain configuration */276		err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);277		if (err)278			return err;279 280		*val = 5;281		*val2 = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? 14 : 15;282		*val2 += u8_get_bits(adc_config, STX104_GAIN);283		return IIO_VAL_FRACTIONAL_LOG2;284	}285 286	return -EINVAL;287}288 289static int stx104_write_raw(struct iio_dev *indio_dev,290	struct iio_chan_spec const *chan, int val, int val2, long mask)291{292	struct stx104_iio *const priv = iio_priv(indio_dev);293	u8 gain;294 295	switch (mask) {296	case IIO_CHAN_INFO_HARDWAREGAIN:297		/* Only four gain states (x1, x2, x4, x8) */298		switch (val) {299		case 1:300			gain = STX104_GAIN_X1;301			break;302		case 2:303			gain = STX104_GAIN_X2;304			break;305		case 4:306			gain = STX104_GAIN_X4;307			break;308		case 8:309			gain = STX104_GAIN_X8;310			break;311		default:312			return -EINVAL;313		}314 315		return regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, gain);316	case IIO_CHAN_INFO_RAW:317		if (!chan->output)318			return -EINVAL;319 320		if (val < 0 || val > U16_MAX)321			return -EINVAL;322 323		return regmap_write(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), val);324	}325 326	return -EINVAL;327}328 329static const struct iio_info stx104_info = {330	.read_raw = stx104_read_raw,331	.write_raw = stx104_write_raw332};333 334/* single-ended input channels configuration */335static const struct iio_chan_spec stx104_channels_sing[] = {336	STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),337	STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),338	STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),339	STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),340	STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),341	STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),342	STX104_IN_CHAN(15, 0)343};344/* differential input channels configuration */345static const struct iio_chan_spec stx104_channels_diff[] = {346	STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),347	STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),348	STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),349	STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)350};351 352static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,353				 unsigned int offset, unsigned int *const reg,354				 unsigned int *const mask)355{356	/* Output lines are located at same register bit offsets as input lines */357	if (offset >= 4)358		offset -= 4;359 360	*reg = base;361	*mask = BIT(offset);362 363	return 0;364}365 366#define STX104_NGPIO 8367static const char *stx104_names[STX104_NGPIO] = {368	"DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"369};370 371static int bank_select_i8254(struct regmap *map)372{373	const u8 select_i8254[] = { 0x3, 0xB, 0xA };374	size_t i;375	int err;376 377	for (i = 0; i < ARRAY_SIZE(select_i8254); i++) {378		err = regmap_write_bits(map, STX104_ADC_CONFIGURATION, STX104_RBK, select_i8254[i]);379		if (err)380			return err;381	}382 383	return 0;384}385 386static int stx104_init_hw(struct stx104_iio *const priv)387{388	int err;389 390	/* configure device for software trigger operation */391	err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONTROL, STX104_SOFTWARE_TRIGGER);392	if (err)393		return err;394 395	/* initialize gain setting to x1 */396	err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, STX104_GAIN_X1);397	if (err)398		return err;399 400	/* initialize DAC outputs to 0V */401	err = regmap_write(priv->aio_data_map, STX104_DAC_BASE, 0);402	if (err)403		return err;404	err = regmap_write(priv->aio_data_map, STX104_DAC_BASE + STX104_AIO_DATA_STRIDE, 0);405	if (err)406		return err;407 408	return bank_select_i8254(priv->aio_ctl_map);409}410 411static int stx104_probe(struct device *dev, unsigned int id)412{413	struct iio_dev *indio_dev;414	struct stx104_iio *priv;415	struct gpio_regmap_config gpio_config;416	struct i8254_regmap_config pit_config;417	void __iomem *stx104_base;418	struct regmap *aio_ctl_map;419	struct regmap *aio_data_map;420	struct regmap *dio_map;421	int err;422	unsigned int adc_status;423 424	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));425	if (!indio_dev)426		return -ENOMEM;427 428	if (!devm_request_region(dev, base[id], STX104_EXTENT,429		dev_name(dev))) {430		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",431			base[id], base[id] + STX104_EXTENT);432		return -EBUSY;433	}434 435	stx104_base = devm_ioport_map(dev, base[id], STX104_EXTENT);436	if (!stx104_base)437		return -ENOMEM;438 439	aio_ctl_map = devm_regmap_init_mmio(dev, stx104_base, &aio_ctl_regmap_config);440	if (IS_ERR(aio_ctl_map))441		return dev_err_probe(dev, PTR_ERR(aio_ctl_map),442				     "Unable to initialize aio_ctl register map\n");443 444	aio_data_map = devm_regmap_init_mmio(dev, stx104_base, &aio_data_regmap_config);445	if (IS_ERR(aio_data_map))446		return dev_err_probe(dev, PTR_ERR(aio_data_map),447				     "Unable to initialize aio_data register map\n");448 449	dio_map = devm_regmap_init_mmio(dev, stx104_base, &dio_regmap_config);450	if (IS_ERR(dio_map))451		return dev_err_probe(dev, PTR_ERR(dio_map),452				     "Unable to initialize dio register map\n");453 454	pit_config.map = devm_regmap_init_mmio(dev, stx104_base, &pit_regmap_config);455	if (IS_ERR(pit_config.map))456		return dev_err_probe(dev, PTR_ERR(pit_config.map),457				     "Unable to initialize i8254 register map\n");458 459	priv = iio_priv(indio_dev);460	priv->aio_ctl_map = aio_ctl_map;461	priv->aio_data_map = aio_data_map;462 463	indio_dev->info = &stx104_info;464	indio_dev->modes = INDIO_DIRECT_MODE;465 466	err = regmap_read(aio_ctl_map, STX104_ADC_STATUS, &adc_status);467	if (err)468		return err;469 470	if (u8_get_bits(adc_status, STX104_SD) == STX104_DIFFERENTIAL) {471		indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);472		indio_dev->channels = stx104_channels_diff;473	} else {474		indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);475		indio_dev->channels = stx104_channels_sing;476	}477 478	indio_dev->name = dev_name(dev);479 480	mutex_init(&priv->lock);481 482	err = stx104_init_hw(priv);483	if (err)484		return err;485 486	err = devm_iio_device_register(dev, indio_dev);487	if (err)488		return err;489 490	gpio_config = (struct gpio_regmap_config) {491		.parent = dev,492		.regmap = dio_map,493		.ngpio = STX104_NGPIO,494		.names = stx104_names,495		.reg_dat_base = GPIO_REGMAP_ADDR(STX104_DIO_REG),496		.reg_set_base = GPIO_REGMAP_ADDR(STX104_DIO_REG),497		.ngpio_per_reg = STX104_NGPIO,498		.reg_mask_xlate = stx104_reg_mask_xlate,499		.drvdata = dio_map,500	};501 502	err = PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));503	if (err)504		return err;505 506	pit_config.parent = dev;507 508	return devm_i8254_regmap_register(dev, &pit_config);509}510 511static struct isa_driver stx104_driver = {512	.probe = stx104_probe,513	.driver = {514		.name = "stx104"515	},516};517 518module_isa_driver(stx104_driver, num_stx104);519 520MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");521MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");522MODULE_LICENSE("GPL v2");523MODULE_IMPORT_NS(I8254);524