Commit 3f262454 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski Committed by Federico Vaga

kernel: use hardware DS18xx interface to read ID/temperature

parent b71af2ab
......@@ -38,5 +38,5 @@ subdirs-ccflags-y = $(ccflags-y)
obj-m := fmc-tdc.o
fmc-tdc-objs = acam.o calibration.o fmc-util.o \
ft-core.o onewire.o ft-time.o ft-irq.o ft-zio.o\
ft-core.o ft-time.o ft-irq.o ft-zio.o\
fmc-bus-link/sdb-lib/access.o fmc-bus-link/sdb-lib/glue.o
......@@ -161,6 +161,7 @@ static inline struct fmctdc_trig *to_fmctdc_trig(struct zio_ti *ti_ptr)
/*
* Main TDC device context
* @unique_id unique identifier from the temperature sensor
* @lock it protects: irq_imr (irq vs user), offset (user vs user),
* wr_mode (user vs user)
* @irq_imr it holds the IMR value since our last modification
......@@ -170,6 +171,7 @@ static inline struct fmctdc_trig *to_fmctdc_trig(struct zio_ti *ti_ptr)
* place where we use it: so, we do not need to protect it.
*/
struct fmctdc_dev {
uint64_t unique_id;
enum ft_transfer_mode mode;
/* HW buffer/FIFO access lock */
spinlock_t lock;
......@@ -249,10 +251,6 @@ void ft_enable_acquisition(struct fmctdc_dev *ft, int enable);
int ft_acam_init(struct fmctdc_dev *ft);
void ft_acam_exit(struct fmctdc_dev *ft);
int ft_onewire_init(struct fmctdc_dev *ft);
void ft_onewire_exit(struct fmctdc_dev *ft);
int ft_read_temp(struct fmctdc_dev *ft, int verbose);
int ft_pll_init(struct fmctdc_dev *ft);
void ft_pll_exit(struct fmctdc_dev *ft);
......
......@@ -242,7 +242,6 @@ struct ft_modlist {
static struct ft_modlist init_subsystems[] = {
{"acam-tdc", ft_acam_init, ft_acam_exit},
{"onewire", ft_onewire_init, ft_onewire_exit},
{"time", ft_time_init, ft_time_exit},
{"channels", ft_channels_init, ft_channels_exit},
{"zio", ft_zio_init, ft_zio_exit}
......
......@@ -25,6 +25,8 @@
#include "fmc-tdc.h"
#include "hw/timestamp_fifo_regs.h"
#include "hw/tdc_onewire_regs.h"
/* The sample size. Mandatory, device-wide */
ZIO_ATTR_DEFINE_STD(ZIO_DEV, ft_zattr_dev_std) = {
......@@ -169,6 +171,35 @@ static int ft_raw_mode_get(struct fmctdc_dev *ft,
}
static int ft_temperature_get(struct fmctdc_dev *ft, int *temp)
{
int stat = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_CSR);
if (!(stat & TDC_OW_CSR_VALID))
return -EIO;
*temp = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_TEMP);
return 0;
}
static int ft_unique_id_get(struct fmctdc_dev *ft, uint64_t *id)
{
int stat = ft_ioread( ft, ft->ft_owregs_base + TDC_OW_REG_CSR);
uint32_t tmp_l, tmp_h;
if( !( stat & TDC_OW_CSR_VALID ) )
return -EIO;
tmp_l = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_ID_L);
tmp_h = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_ID_H);
*id = ((uint64_t)tmp_h << 32) | tmp_l;
return 0;
}
/* TDC input attributes: only the user offset is special */
static int ft_zio_info_channel(struct device *dev, struct zio_attribute *zattr,
uint32_t *usr_val)
......@@ -214,6 +245,7 @@ static int ft_zio_info_get(struct device *dev, struct zio_attribute *zattr,
struct zio_device *zdev;
struct fmctdc_dev *ft;
struct zio_attribute *attr;
int ret;
if (__ft_get_type(dev) == FT_TYPE_INPUT)
return ft_zio_info_channel(dev, zattr, usr_val);
......@@ -224,7 +256,9 @@ static int ft_zio_info_get(struct device *dev, struct zio_attribute *zattr,
switch (zattr->id) {
case FT_ATTR_PARAM_TEMP:
ft_read_temp(ft, ft->verbose);
ret = ft_temperature_get(ft, &ft->temp);
if (ret < 0)
return ret;
*usr_val = ft->temp;
break;
case FT_ATTR_DEV_COARSE:
......@@ -685,6 +719,8 @@ int ft_zio_init(struct fmctdc_dev *ft)
ft_update_offsets(ft, i);
}
ft_unique_id_get(ft, &ft->unique_id);
return 0;
err_dev_reg:
......
/*
Register definitions for slave core: TDC Onewire Master
* File : tdc_onewire_regs.h
* Author : auto-generated by wbgen2 from wbgen/tdc_onewire_wb.wb
* Created : Tue Sep 11 11:16:49 2018
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wbgen/tdc_onewire_wb.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_TDC_ONEWIRE_WB_WB
#define __WBGEN2_REGDEFS_TDC_ONEWIRE_WB_WB
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <inttypes.h>
#endif
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Status Register */
/* definitions for field: Temperature & ID valid in reg: Status Register */
#define TDC_OW_CSR_VALID WBGEN2_GEN_MASK(0, 1)
/* definitions for register: Board Temperature */
/* definitions for register: Board Unique ID (MSW) */
/* definitions for register: Board Unique ID (LSW) */
/* [0x0]: REG Status Register */
#define TDC_OW_REG_CSR 0x00000000
/* [0x4]: REG Board Temperature */
#define TDC_OW_REG_TEMP 0x00000004
/* [0x8]: REG Board Unique ID (MSW) */
#define TDC_OW_REG_ID_H 0x00000008
/* [0xc]: REG Board Unique ID (LSW) */
#define TDC_OW_REG_ID_L 0x0000000c
#endif
/*
* Access to a DS182x 1-Wire thermometers.
*
* Copyright (C) 2012-2013 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/delay.h>
#include "fmc-tdc.h"
#include "hw/tdc_regs.h"
#define R_CSR 0x0
#define R_CDR 0x4
#define CSR_DAT_MSK (1<<0)
#define CSR_RST_MSK (1<<1)
#define CSR_OVD_MSK (1<<2)
#define CSR_CYC_MSK (1<<3)
#define CSR_PWR_MSK (1<<4)
#define CSR_IRQ_MSK (1<<6)
#define CSR_IEN_MSK (1<<7)
#define CSR_SEL_OFS 8
#define CSR_SEL_MSK (0xF<<8)
#define CSR_POWER_OFS 16
#define CSR_POWER_MSK (0xFFFF<<16)
#define CDR_NOR_MSK (0xFFFF<<0)
#define CDR_OVD_OFS 16
#define CDR_OVD_MSK (0xFFFF<<16)
#define CLK_DIV_NOR (624/2)
#define CLK_DIV_OVD (124/2)
#define CMD_ROM_SEARCH 0xF0
#define CMD_ROM_READ 0x33
#define CMD_ROM_MATCH 0x55
#define CMD_ROM_SKIP 0xCC
#define CMD_ROM_ALARM_SEARCH 0xEC
#define CMD_CONVERT_TEMP 0x44
#define CMD_WRITE_SCRATCHPAD 0x4E
#define CMD_READ_SCRATCHPAD 0xBE
#define CMD_COPY_SCRATCHPAD 0x48
#define CMD_RECALL_EEPROM 0xB8
#define CMD_READ_POWER_SUPPLY 0xB4
#define FT_OW_PORT 0 /* what is this slow? */
static void ow_writel(struct fmctdc_dev *ft, uint32_t val, unsigned long reg)
{
ft_iowrite(ft, val, ft->ft_owregs_base + reg);
}
static uint32_t ow_readl(struct fmctdc_dev *ft, unsigned long reg)
{
return ft_ioread(ft, ft->ft_owregs_base + reg);
}
static int ow_reset(struct fmctdc_dev *ft, int port)
{
uint32_t reg, data;
data = ((port << CSR_SEL_OFS) & CSR_SEL_MSK)
| CSR_CYC_MSK | CSR_RST_MSK;
ow_writel(ft, data, R_CSR);
while (ow_readl(ft, R_CSR) & CSR_CYC_MSK)
/* FIXME: timeout */ ;
reg = ow_readl(ft, R_CSR);
return ~reg & CSR_DAT_MSK;
}
static int slot(struct fmctdc_dev *ft, int port, int bit)
{
uint32_t reg, data;
data = ((port << CSR_SEL_OFS) & CSR_SEL_MSK)
| CSR_CYC_MSK | (bit & CSR_DAT_MSK);
ow_writel(ft, data, R_CSR);
while (ow_readl(ft, R_CSR) & CSR_CYC_MSK)
/* FIXME: timeout */ ;
reg = ow_readl(ft, R_CSR);
return reg & CSR_DAT_MSK;
}
static int read_bit(struct fmctdc_dev *ft, int port)
{
return slot(ft, port, 0x1);
}
static int write_bit(struct fmctdc_dev *ft, int port, int bit)
{
return slot(ft, port, bit);
}
static int ow_read_byte(struct fmctdc_dev *ft, int port)
{
int byte = 0, i;
for (i = 0; i < 8; i++)
byte |= (read_bit(ft, port) << i);
return byte;
}
static int ow_write_byte(struct fmctdc_dev *ft, int port, int byte)
{
int data = 0;
int i;
for (i = 0; i < 8; i++) {
data |= write_bit(ft, port, (byte & 0x1)) << i;
byte >>= 1;
}
return 0; /* success */
}
static int ow_write_block(struct fmctdc_dev *ft, int port, uint8_t * block,
int len)
{
int i;
for (i = 0; i < len; i++)
ow_write_byte(ft, port, block[i]);
return 0;
}
static int ow_read_block(struct fmctdc_dev *ft, int port, uint8_t * block,
int len)
{
int i;
for (i = 0; i < len; i++)
block[i] = ow_read_byte(ft, port);
return 0;
}
static int ds18x_read_serial(struct fmctdc_dev *ft)
{
if (!ow_reset(ft, 0)) {
dev_err(&ft->fmc->dev,
"Failure in resetting one-wire channel\n");
return -EIO;
}
ow_write_byte(ft, FT_OW_PORT, CMD_ROM_READ);
return ow_read_block(ft, FT_OW_PORT, ft->ds18_id, 8);
}
static int ds18x_access(struct fmctdc_dev *ft)
{
if (!ow_reset(ft, 0))
goto out;
if (0) {
/* select the rom among several of them */
if (ow_write_byte(ft, FT_OW_PORT, CMD_ROM_MATCH) < 0)
goto out;
return ow_write_block(ft, FT_OW_PORT, ft->ds18_id, 8);
} else {
/* we have one only, so skip rom */
return ow_write_byte(ft, FT_OW_PORT, CMD_ROM_SKIP);
}
out:
dev_err(&ft->fmc->dev, "Failure in one-wire communication\n");
return -EIO;
}
static void __temp_command_and_next_t(struct fmctdc_dev *ft, int cfg_reg)
{
int ms;
ds18x_access(ft);
ow_write_byte(ft, FT_OW_PORT, CMD_CONVERT_TEMP);
/* The conversion takes some time, so mark when will it be ready */
ms = 94 * (1 << (cfg_reg >> 5));
ft->next_t = jiffies + msecs_to_jiffies(ms);
}
int ft_read_temp(struct fmctdc_dev *ft, int verbose)
{
int i, temp;
unsigned long j;
uint8_t data[9];
struct device *dev = &ft->fmc->dev;
/* If first conversion, ask for it first */
if (ft->next_t == 0)
__temp_command_and_next_t(ft, 0x7f /* we ignore: max time */ );
/* Wait for it to be ready: (FIXME: we need a time policy here) */
j = jiffies;
if (time_before(j, ft->next_t)) {
/* If we cannot sleep, return the previous value */
if (in_atomic())
return ft->temp;
msleep(jiffies_to_msecs(ft->next_t - j));
}
ds18x_access(ft);
ow_write_byte(ft, FT_OW_PORT, CMD_READ_SCRATCHPAD);
ow_read_block(ft, FT_OW_PORT, data, 9);
if (verbose > 1) {
dev_info(dev, "%s: Scratchpad: ", __func__);
for (i = 0; i < 9; i++)
printk("%02x%c", data[i], i == 8 ? '\n' : ':');
}
temp = ((int)data[1] << 8) | ((int)data[0]);
if (temp & 0x1000)
temp = -0x10000 + temp;
ft->temp = temp;
ft->temp_ready = 1;
if (verbose) {
dev_info(dev, "%s: Temperature 0x%x (%i bits: %i.%03i)\n",
__func__, temp, 9 + (data[4] >> 5), temp / 16,
(temp & 0xf) * 1000 / 16);
}
__temp_command_and_next_t(ft, data[4]); /* start next conversion */
return temp;
}
int ft_onewire_init(struct fmctdc_dev *ft)
{
int i;
ow_writel(ft, ((CLK_DIV_NOR & CDR_NOR_MSK)
| ((CLK_DIV_OVD << CDR_OVD_OFS) & CDR_OVD_MSK)), R_CDR);
if (ds18x_read_serial(ft) < 0)
return -EIO;
if (ft->verbose) {
dev_info(&ft->fmc->dev, "%s: Found DS18xx sensor: ", __func__);
for (i = 0; i < 8; i++)
printk("%02x%c", ft->ds18_id[i], i == 7 ? '\n' : ':');
}
/* read the temperature once, to ensure it works, and print it */
ft_read_temp(ft, ft->verbose);
return 0;
}
void ft_onewire_exit(struct fmctdc_dev *fd)
{
/* Nothing to do */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment