brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · 56f822a Raw
354 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *	w1_ds2408.c - w1 family 29 (DS2408) driver4 *5 * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com>6 */7 8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/moduleparam.h>11#include <linux/device.h>12#include <linux/types.h>13#include <linux/delay.h>14#include <linux/slab.h>15 16#include <linux/w1.h>17 18#define W1_FAMILY_DS2408	0x2919 20#define W1_F29_RETRIES		321 22#define W1_F29_REG_LOGIG_STATE             0x88 /* R */23#define W1_F29_REG_OUTPUT_LATCH_STATE      0x89 /* R */24#define W1_F29_REG_ACTIVITY_LATCH_STATE    0x8A /* R */25#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */26#define W1_F29_REG_COND_SEARCH_POL_SELECT  0x8C /* RW */27#define W1_F29_REG_CONTROL_AND_STATUS      0x8D /* RW */28 29#define W1_F29_FUNC_READ_PIO_REGS          0xF030#define W1_F29_FUNC_CHANN_ACCESS_READ      0xF531#define W1_F29_FUNC_CHANN_ACCESS_WRITE     0x5A32/* also used to write the control/status reg (0x8D): */33#define W1_F29_FUNC_WRITE_COND_SEARCH_REG  0xCC34#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC335 36#define W1_F29_SUCCESS_CONFIRM_BYTE        0xAA37 38static int _read_reg(struct w1_slave *sl, u8 address, unsigned char *buf)39{40	u8 wrbuf[3];41 42	dev_dbg(&sl->dev, "Reading with slave: %p, reg addr: %0#4x, buff addr: %p",43		sl, (unsigned int)address, buf);44 45	if (!buf)46		return -EINVAL;47 48	mutex_lock(&sl->master->bus_mutex);49	dev_dbg(&sl->dev, "mutex locked");50 51	if (w1_reset_select_slave(sl)) {52		mutex_unlock(&sl->master->bus_mutex);53		return -EIO;54	}55 56	wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;57	wrbuf[1] = address;58	wrbuf[2] = 0;59	w1_write_block(sl->master, wrbuf, 3);60	*buf = w1_read_8(sl->master);61 62	mutex_unlock(&sl->master->bus_mutex);63	dev_dbg(&sl->dev, "mutex unlocked");64	return 1;65}66 67static ssize_t state_read(struct file *filp, struct kobject *kobj,68			  struct bin_attribute *bin_attr, char *buf, loff_t off,69			  size_t count)70{71	dev_dbg(&kobj_to_w1_slave(kobj)->dev,72		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",73		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);74	if (count != 1 || off != 0)75		return -EFAULT;76	return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);77}78 79static ssize_t output_read(struct file *filp, struct kobject *kobj,80			   struct bin_attribute *bin_attr, char *buf,81			   loff_t off, size_t count)82{83	dev_dbg(&kobj_to_w1_slave(kobj)->dev,84		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",85		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);86	if (count != 1 || off != 0)87		return -EFAULT;88	return _read_reg(kobj_to_w1_slave(kobj),89					 W1_F29_REG_OUTPUT_LATCH_STATE, buf);90}91 92static ssize_t activity_read(struct file *filp, struct kobject *kobj,93			     struct bin_attribute *bin_attr, char *buf,94			     loff_t off, size_t count)95{96	dev_dbg(&kobj_to_w1_slave(kobj)->dev,97		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",98		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);99	if (count != 1 || off != 0)100		return -EFAULT;101	return _read_reg(kobj_to_w1_slave(kobj),102					 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);103}104 105static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,106				     struct bin_attribute *bin_attr, char *buf,107				     loff_t off, size_t count)108{109	dev_dbg(&kobj_to_w1_slave(kobj)->dev,110		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",111		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);112	if (count != 1 || off != 0)113		return -EFAULT;114	return _read_reg(kobj_to_w1_slave(kobj),115		W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);116}117 118static ssize_t cond_search_polarity_read(struct file *filp,119					 struct kobject *kobj,120					 struct bin_attribute *bin_attr,121					 char *buf, loff_t off, size_t count)122{123	if (count != 1 || off != 0)124		return -EFAULT;125	return _read_reg(kobj_to_w1_slave(kobj),126		W1_F29_REG_COND_SEARCH_POL_SELECT, buf);127}128 129static ssize_t status_control_read(struct file *filp, struct kobject *kobj,130				   struct bin_attribute *bin_attr, char *buf,131				   loff_t off, size_t count)132{133	if (count != 1 || off != 0)134		return -EFAULT;135	return _read_reg(kobj_to_w1_slave(kobj),136		W1_F29_REG_CONTROL_AND_STATUS, buf);137}138 139#ifdef CONFIG_W1_SLAVE_DS2408_READBACK140static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)141{142	u8 w1_buf[3];143 144	if (w1_reset_resume_command(sl->master))145		return false;146 147	w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;148	w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;149	w1_buf[2] = 0;150 151	w1_write_block(sl->master, w1_buf, 3);152 153	return (w1_read_8(sl->master) == expected);154}155#else156static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)157{158	return true;159}160#endif161 162static ssize_t output_write(struct file *filp, struct kobject *kobj,163			    struct bin_attribute *bin_attr, char *buf,164			    loff_t off, size_t count)165{166	struct w1_slave *sl = kobj_to_w1_slave(kobj);167	u8 w1_buf[3];168	unsigned int retries = W1_F29_RETRIES;169	ssize_t bytes_written = -EIO;170 171	if (count != 1 || off != 0)172		return -EFAULT;173 174	dev_dbg(&sl->dev, "locking mutex for write_output");175	mutex_lock(&sl->master->bus_mutex);176	dev_dbg(&sl->dev, "mutex locked");177 178	if (w1_reset_select_slave(sl))179		goto out;180 181	do {182		w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;183		w1_buf[1] = *buf;184		w1_buf[2] = ~(*buf);185 186		w1_write_block(sl->master, w1_buf, 3);187 188		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE &&189		    optional_read_back_valid(sl, *buf)) {190			bytes_written = 1;191			goto out;192		}193 194		if (w1_reset_resume_command(sl->master))195			goto out; /* unrecoverable error */196		/* try again, the slave is ready for a command */197	} while (--retries);198 199out:200	mutex_unlock(&sl->master->bus_mutex);201 202	dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n",203		(bytes_written > 0) ? "succeeded" : "error", retries);204 205	return bytes_written;206}207 208 209/*210 * Writing to the activity file resets the activity latches.211 */212static ssize_t activity_write(struct file *filp, struct kobject *kobj,213			      struct bin_attribute *bin_attr, char *buf,214			      loff_t off, size_t count)215{216	struct w1_slave *sl = kobj_to_w1_slave(kobj);217	unsigned int retries = W1_F29_RETRIES;218 219	if (count != 1 || off != 0)220		return -EFAULT;221 222	mutex_lock(&sl->master->bus_mutex);223 224	if (w1_reset_select_slave(sl))225		goto error;226 227	while (retries--) {228		w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);229		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {230			mutex_unlock(&sl->master->bus_mutex);231			return 1;232		}233		if (w1_reset_resume_command(sl->master))234			goto error;235	}236 237error:238	mutex_unlock(&sl->master->bus_mutex);239	return -EIO;240}241 242static ssize_t status_control_write(struct file *filp, struct kobject *kobj,243				    struct bin_attribute *bin_attr, char *buf,244				    loff_t off, size_t count)245{246	struct w1_slave *sl = kobj_to_w1_slave(kobj);247	u8 w1_buf[4];248	unsigned int retries = W1_F29_RETRIES;249 250	if (count != 1 || off != 0)251		return -EFAULT;252 253	mutex_lock(&sl->master->bus_mutex);254 255	if (w1_reset_select_slave(sl))256		goto error;257 258	while (retries--) {259		w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;260		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;261		w1_buf[2] = 0;262		w1_buf[3] = *buf;263 264		w1_write_block(sl->master, w1_buf, 4);265		if (w1_reset_resume_command(sl->master))266			goto error;267 268		w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;269		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;270		w1_buf[2] = 0;271 272		w1_write_block(sl->master, w1_buf, 3);273		if (w1_read_8(sl->master) == *buf) {274			/* success! */275			mutex_unlock(&sl->master->bus_mutex);276			return 1;277		}278	}279error:280	mutex_unlock(&sl->master->bus_mutex);281 282	return -EIO;283}284 285/*286 * This is a special sequence we must do to ensure the P0 output is not stuck287 * in test mode. This is described in rev 2 of the ds2408's datasheet288 * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under289 * "APPLICATION INFORMATION/Power-up timing".290 */291static int w1_f29_disable_test_mode(struct w1_slave *sl)292{293	int res;294	u8 magic[10] = {0x96, };295	u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));296 297	memcpy(&magic[1], &rn, 8);298	magic[9] = 0x3C;299 300	mutex_lock(&sl->master->bus_mutex);301 302	res = w1_reset_bus(sl->master);303	if (res)304		goto out;305	w1_write_block(sl->master, magic, ARRAY_SIZE(magic));306 307	res = w1_reset_bus(sl->master);308out:309	mutex_unlock(&sl->master->bus_mutex);310	return res;311}312 313static BIN_ATTR_RO(state, 1);314static BIN_ATTR_RW(output, 1);315static BIN_ATTR_RW(activity, 1);316static BIN_ATTR_RO(cond_search_mask, 1);317static BIN_ATTR_RO(cond_search_polarity, 1);318static BIN_ATTR_RW(status_control, 1);319 320static struct bin_attribute *w1_f29_bin_attrs[] = {321	&bin_attr_state,322	&bin_attr_output,323	&bin_attr_activity,324	&bin_attr_cond_search_mask,325	&bin_attr_cond_search_polarity,326	&bin_attr_status_control,327	NULL,328};329 330static const struct attribute_group w1_f29_group = {331	.bin_attrs = w1_f29_bin_attrs,332};333 334static const struct attribute_group *w1_f29_groups[] = {335	&w1_f29_group,336	NULL,337};338 339static const struct w1_family_ops w1_f29_fops = {340	.add_slave      = w1_f29_disable_test_mode,341	.groups		= w1_f29_groups,342};343 344static struct w1_family w1_family_29 = {345	.fid = W1_FAMILY_DS2408,346	.fops = &w1_f29_fops,347};348module_w1_family(w1_family_29);349 350MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");351MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");352MODULE_LICENSE("GPL");353MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408));354