Files
linux-nv-oot/drivers/net/can/mttcan/native/m_ttcan_sys.c
Manish Bhardwaj 0e0d2f2c07 nvidia-oot: add support for mttcan driver
Using this patch we are adding support for
mttcan driver in oot kernel.

JIRA ESLC-6885

Signed-off-by: Manish Bhardwaj <mbhardwaj@nvidia.com>
Change-Id: I83a6d43aa99278a546778cf1700e2bd106ec42a9
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2785360
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2022-10-03 21:31:05 -07:00

742 lines
20 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include "../include/m_ttcan.h"
#define spec_bar() asm volatile(ALTERNATIVE("dsb nsh\nisb\n", \
SB_BARRIER_INSN"nop\n", \
ARM64_HAS_SB))
static int mttcan_check_fec_validity(struct mttcan_priv *priv,
unsigned int fec);
static ssize_t show_std_fltr(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
int cur_filter_size = priv->ttcan->fltr_config.std_fltr_size;
ssize_t ret, total = 0;
int i = 0;
ret = sprintf(buf, "%s\n", "Standard Filters");
if (ret < 0) {
pr_err("sprintf() failed at line %d\n", __LINE__);
return -ENOMEM;
}
total += ret;
while (cur_filter_size--) {
ret = sprintf(buf+total, "%d. 0x%x\n", i,
ttcan_get_std_id_filter(priv->ttcan, i));
if (ret < 0) {
pr_err("sprintf() failed at line %d\n", __LINE__);
return -ENOMEM;
}
total += ret;
i++;
}
return total;
}
static ssize_t show_xtd_fltr(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
int cur_filter_size = priv->ttcan->fltr_config.xtd_fltr_size;
ssize_t ret, total = 0;
int i = 0;
ret = sprintf(buf, "%s\n", "Extended Filters");
if (ret < 0) {
pr_err("sprintf() failed at line %d\n", __LINE__);
return -ENOMEM;
}
total += ret;
while (cur_filter_size--) {
ret = sprintf(buf+total, "%d. 0x%llx\n", i,
ttcan_get_xtd_id_filter(priv->ttcan, i));
if (ret < 0) {
pr_err("sprintf() failed at line %d\n", __LINE__);
return -ENOMEM;
}
total += ret;
i++;
}
return total;
}
static ssize_t show_gfc_fltr(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "Global filter",
ttcan_get_gfc(priv->ttcan));
}
static ssize_t store_gfc_fltr(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
struct ttcan_controller *ttcan = priv->ttcan;
unsigned int anfs, anfe;
unsigned int rrfs, rrfe;
u32 gfc;
int ret;
if (ndev->flags & IFF_UP) {
dev_err(dev, "GFC cannot be configured as device is running\n");
return -EBUSY;
}
ret = sscanf(buf, "anfs=%u anfe=%u rrfs=%u rrfe=%u", &anfs,
&anfe, &rrfs, &rrfe);
if ((ret < 4) || ((anfs | anfe) > 3) || ((rrfs | rrfe) > 1)) {
dev_err(dev, "Invalid Global filter\n");
pr_err("usage:anfs=0..3 anfe=0..3 rrfs=0/1 rrfe=0/1\n");
return -EINVAL;
}
if (((anfs == GFC_ANFS_RXFIFO_0) || (anfe == GFC_ANFE_RXFIFO_0))
&& (ttcan->mram_cfg[MRAM_RXF0].num == 0U)) {
dev_err(priv->device, "RX FIFO 0 is not used currently.");
dev_err(priv->device, " Change it via DT\n");
return -EINVAL;
}
if (((anfs == GFC_ANFS_RXFIFO_1) || (anfe == GFC_ANFE_RXFIFO_1))
&& (ttcan->mram_cfg[MRAM_RXF1].num == 0U)) {
dev_err(priv->device, "RX FIFO 1 is not used currently.");
dev_err(priv->device, " Change it via DT\n");
return -EINVAL;
}
gfc = 0;
gfc = (anfs << MTT_GFC_ANFS_SHIFT) & MTT_GFC_ANFS_MASK;
gfc |= (anfe << MTT_GFC_ANFE_SHIFT) & MTT_GFC_ANFE_MASK;
gfc |= (rrfs << MTT_GFC_RRFS_SHIFT) & MTT_GFC_RRFS_MASK;
gfc |= (rrfe << MTT_GFC_RRFE_SHIFT) & MTT_GFC_RRFE_MASK;
priv->gfc_reg = gfc;
ttcan_set_gfc(priv->ttcan, gfc);
return count;
}
static ssize_t show_xidam(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "XIDAM",
ttcan_get_xidam(priv->ttcan));
}
static ssize_t store_xidam(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
unsigned int xidam;
if (ndev->flags & IFF_UP) {
dev_err(dev, "XIDAM is protected, device is running\n");
return -EBUSY;
}
/* usage: xidam=MASK */
if (sscanf(buf, "xidam=%u", &xidam) != 1) {
dev_err(dev, "Invalid XIDAM MASK\n");
pr_err("usage: xidam=MASK\n");
return -EINVAL;
}
priv->xidam_reg = xidam;
ttcan_set_xidam(priv->ttcan, xidam);
return count;
}
static int mttcan_check_fec_validity(struct mttcan_priv *priv,
unsigned int fec)
{
struct ttcan_controller *ttcan = priv->ttcan;
if (fec > FEC_RXBUF) {
dev_err(priv->device, "sfec/efec should be in range 0-7\n");
return -EINVAL;
}
if (((fec == FEC_RXFIFO_0) || (fec == FEC_RXFIFO_0_PRIO)) &&
(ttcan->mram_cfg[MRAM_RXF0].num == 0U)) {
dev_err(priv->device, "RX FIFO 0 is not used currently.");
dev_err(priv->device, " Change it via DT\n");
return -EINVAL;
}
if (((fec == FEC_RXFIFO_1) || (fec == FEC_RXFIFO_1_PRIO)) &&
(ttcan->mram_cfg[MRAM_RXF1].num == 0U)) {
dev_err(priv->device, "RX FIFO 1 is not used currently.");
dev_err(priv->device, " Change it via DT\n");
return -EINVAL;
}
if ((fec == FEC_RXBUF) && (ttcan->mram_cfg[MRAM_RXB].num == 0U)) {
dev_err(priv->device, "RX Buffer is not used currently.");
dev_err(priv->device, " Change it via DT\n");
return -EINVAL;
}
return 0;
}
static ssize_t store_std_fltr(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
struct net_device *ndev = to_net_dev(dev);
unsigned int sft, sfec;
unsigned int sfid1, sfid2;
int idx = -1, cur_filter_size;
int items;
int ret;
if (ndev->flags & IFF_UP) {
dev_err(dev, "device is running\n");
return -EBUSY;
}
/* usage: sft="0/1/2/3" sfec=1...7 sfid1="ID1" sfid2="ID2" idx=%u
*/
ret = sscanf(buf, "sft=%u sfec=%u sfid1=%X sfid2=%X idx=%u", &sft,
&sfec, &sfid1, &sfid2, &idx);
if (ret < 4) {
/* Not passing index is allowed */
dev_err(dev, "Invalid std filter\n");
pr_err("usage:sft=0..3 sfec=0..7 sfid1=ID1h sfid2=ID2h idx=i\n");
return -EINVAL;
}
items = ret;
cur_filter_size = priv->ttcan->fltr_config.std_fltr_size;
if ((idx > cur_filter_size) || (idx == -1)) {
if (cur_filter_size >= priv->ttcan->mram_cfg[MRAM_SIDF].num) {
dev_err(dev, "Max Invalid std filter Index\n");
return -ENOSPC;
}
}
ret = mttcan_check_fec_validity(priv, sfec);
if (ret < 0) {
dev_err(dev, "Invalid sfec value\n");
return -EINVAL;
}
if (items == 5) {
if (idx > cur_filter_size) {
dev_err(dev, "Invalid std filter Index\n");
return -EINVAL;
}
/* array access based on user provided index/data */
spec_bar();
ttcan_set_std_id_filter(priv->ttcan, priv->std_shadow,
idx, (u8)sft, (u8)sfec, sfid1, sfid2);
if (idx == cur_filter_size)
priv->ttcan->fltr_config.std_fltr_size++;
} else {
/* array access based on user provided index/data */
spec_bar();
ttcan_set_std_id_filter(priv->ttcan, priv->std_shadow,
cur_filter_size, (u8) sft, (u8)sfec, sfid1, sfid2);
priv->ttcan->fltr_config.std_fltr_size++;
}
return count;
}
static ssize_t store_xtd_fltr(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
struct net_device *ndev = to_net_dev(dev);
unsigned int eft, efec;
unsigned int efid1, efid2;
int idx = -1, cur_filter_size;
int items;
int ret;
if (ndev->flags & IFF_UP) {
dev_err(dev, "device is running\n");
return -EBUSY;
}
/* usage: eft="0/1/2/3" efec=1...7 efid1="ID1h" efid2="ID2h" idx=%u
*/
ret = sscanf(buf, "eft=%u efec=%u efid1=%X efid2=%X idx=%u", &eft,
&efec, &efid1, &efid2, &idx);
if (ret < 4) {
/* Not passing index is allowed */
dev_err(dev, "Invalid xtd filter\n");
pr_err("usage:eft=0..3 efec=0..7 efid1=ID1h efid2=ID2h idx=i\n");
return -EINVAL;
}
items = ret;
cur_filter_size = priv->ttcan->fltr_config.xtd_fltr_size;
if ((idx > cur_filter_size) || (idx == -1)) {
if (cur_filter_size >= priv->ttcan->mram_cfg[MRAM_XIDF].num) {
dev_err(dev, "Max Invalid xtd filter Index\n");
return -ENOSPC;
}
}
ret = mttcan_check_fec_validity(priv, efec);
if (ret < 0) {
dev_err(dev, "Invalid efec value\n");
return -EINVAL;
}
if (items == 5) {
if (idx > cur_filter_size) {
dev_err(dev, "Invalid xtd filter Index\n");
return -EINVAL;
}
/* array access based on user provided index/data */
spec_bar();
ttcan_set_xtd_id_filter(priv->ttcan, priv->xtd_shadow,
idx, (u8) eft, (u8) efec, efid1, efid2);
if (idx == cur_filter_size)
priv->ttcan->fltr_config.xtd_fltr_size++;
} else {
/* array access based on user provided index/data */
spec_bar();
ttcan_set_xtd_id_filter(priv->ttcan, priv->xtd_shadow,
cur_filter_size, (u8) eft, (u8) efec, efid1, efid2);
priv->ttcan->fltr_config.xtd_fltr_size++;
}
return count;
}
static ssize_t show_tx_cancel(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "TXBCF",
ttcan_read_tx_cancelled_reg(priv->ttcan));
}
static ssize_t store_tx_cancel(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
unsigned int txcbr;
/* usage: txbcr=bit_mask for buffer */
if (sscanf(buf, "txbcr=%X", &txcbr) != 1) {
dev_err(dev, "Invalid TXBCR value\n");
pr_err("%s usage: txbcr=bit_mask to cancel\n", buf);
return -EINVAL;
}
ttcan_set_tx_cancel_request(priv->ttcan, txcbr);
return count;
}
static ssize_t show_ttrmc(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "TTRMC",
ttcan_get_ttrmc(priv->ttcan));
}
static ssize_t store_ttrmc(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
unsigned int rmps, xtd, rid;
if (ndev->flags & IFF_UP) {
dev_err(dev, "TTRMC is protected, device is running\n");
return -EBUSY;
}
/* usage: rmps=0/1 xtd=0/1 rid=ReferenceID */
if (sscanf(buf, "rmps=%u xtd=%u rid=%X", &rmps, &xtd, &rid) != 3) {
dev_err(dev, "Invalid TTRMC\n");
pr_err("usage: rmps=0/1 xtd=0/1 rid=ReferenceID in hex\n");
return -EINVAL;
}
ttcan_set_ref_mesg(priv->ttcan, rid, rmps, xtd);
return count;
}
static ssize_t show_ttocf(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "TTOCF",
ttcan_get_ttocf(priv->ttcan));
}
static ssize_t store_ttocf(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
unsigned int evtp, ecc, egtf, awl, eecs, irto, ldsdl, tm, gen, om;
if (ndev->flags & IFF_UP) {
dev_err(dev, "TTCOF is protected, device is running\n");
return -EBUSY;
}
/* usage: evtp=0/1 ecc=0/1 egtf=0/1 awl=0..255 eecs=0 irto=0..127
* ldsdl=0..7 tm=0/1 gen=0/1 om=0..4 */
if (sscanf(buf,
"evtp=%u ecc=%u egtf=%u awl=%u eecs=%u irto=%u ldsdl=%u tm=%u gen=%u om=%u",
&evtp, &ecc, &egtf, &awl, &eecs, &irto, &ldsdl,
&tm, &gen, &om) != 10) {
dev_err(dev, "Invalid TTOCF\n");
pr_err("usage: evtp=0/1 ecc=0/1 egtf=0/1 awl=0..255 eecs=0 irto=0..127 ldsdl=0..7 tm=0/1 gen=0/1 om=0..4\n");
return -EINVAL;
}
ttcan_set_tt_config(priv->ttcan, evtp, ecc, egtf,
awl, eecs, irto, ldsdl, tm, gen, om);
return count;
}
static ssize_t show_ttmlm(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "TTMLM",
ttcan_get_ttmlm(priv->ttcan));
}
static ssize_t store_ttmlm(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
unsigned int entt, txew, css, ccm;
if (ndev->flags & IFF_UP) {
dev_err(dev, "TTMLM is protected, device is running\n");
return -EBUSY;
}
/* usage: entt=0...4095 txew=0..15 css=0..2 ccm=0..63(2*pow(n)-1) */
if (sscanf(buf, "entt=%u txew=%u css=%u ccm=%u",
&entt, &txew, &css, &ccm) != 4) {
dev_err(dev, "Invalid TTMLM\n");
pr_err("usage: entt=0...4095 txew=0..15 css=0..2 ccm=0..63(2*pow(n)-1)\n");
return -EINVAL;
}
ttcan_set_matrix_limits(priv->ttcan, entt, txew, css, ccm);
return count;
}
static ssize_t show_tttmc(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%s\n0x%x\n", "TTTMC",
ttcan_get_tttmc(priv->ttcan));
}
static ssize_t store_tttmc(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
u32 tme, tttmc;
if (ndev->flags & IFF_UP) {
dev_err(dev, "TTTMC is protected, device is running\n");
return -EBUSY;
}
/* usage: tme=number of elements */
if (sscanf(buf, "tme=%u", &tme) != 1) {
dev_err(dev, "Invalid TTTMC\n");
pr_err("usage: tme=0..64 (Num Elements)\n");
return -EINVAL;
}
if (tme > 64)
tme = 64;
tttmc = ttcan_get_tttmc(priv->ttcan);
tttmc &= ~MTT_TTTMC_TME_MASK;
tttmc |= (tme << MTT_TTTMC_TME_SHIFT) &
MTT_TTTMC_TME_MASK;
ttcan_set_tttmc(priv->ttcan, tttmc);
return count;
}
static ssize_t show_cccr_txbar(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
unsigned int init = 0;
init = ttcan_get_cccr(priv->ttcan) & 0x1;
return sprintf(buf, "CCCR.INIT %s\n", init ? "set" : "reset");
}
static ssize_t store_cccr_txbar(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
char str[32];
int txbar = 0;
if ((sscanf(buf, "%s txbar=%d", str, &txbar) != 2) || (txbar > 32)) {
dev_err(dev, "Invalid String or txbar\n");
pr_err("usage: reset/set txbar=0..32 (Num Elements)\n");
return -EINVAL;
}
/* usage: set/reset */
if (strcmp("set", str) == 0)
ttcan_set_config_change_enable(priv->ttcan);
else if (strcmp("reset", str) == 0)
ttcan_reset_config_change_enable(priv->ttcan);
else {
dev_err(dev, "Invalid String\n");
pr_err("valid strings: set/reset\n");
return -EINVAL;
}
txbar = (1UL << txbar) - 1;
ttcan_set_txbar(priv->ttcan, txbar);
return count;
}
static ssize_t show_txbar(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "Not implemented\n");
}
static ssize_t store_txbar(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
unsigned int txbar = 0;
/* usage: txbar=1...32*/
if ((sscanf(buf, "txbar=%u", &txbar) != 1) || (txbar > 32)) {
dev_err(dev, "Invalid TXBAR\n");
pr_err("usage: txbar=1..32\n");
return -EINVAL;
}
txbar = (1UL << txbar) - 1;
ttcan_set_txbar(priv->ttcan, txbar);
return count;
}
static ssize_t show_trigger_mem(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
int cur = priv->ttcan->tt_mem_elements;
ssize_t ret, total = 0;
int i = 0;
ret = sprintf(buf, "%s\n", "Trigger Memory Elements");
if (ret < 0) {
pr_err("sprintf() failed at line %d\n", __LINE__);
return -ENOMEM;
}
total += ret;
while (cur--) {
ret = sprintf(buf+total, "%d. 0x%llx\n", i,
ttcan_get_trigger_mem(priv->ttcan, i));
if (ret < 0) {
pr_err("sprintf() failed at line %d\n", __LINE__);
return -ENOMEM;
}
total += ret;
i++;
}
return total;
}
static ssize_t store_trigger_mem(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned int tm, cc, tmin, tmex, type;
unsigned int ftype, mnr;
int idx = -1, cur;
int ret;
struct net_device *ndev = to_net_dev(dev);
struct mttcan_priv *priv = netdev_priv(ndev);
if (ndev->flags & IFF_UP) {
dev_err(dev, "Trigger Mem is protected, device is running\n");
return -EBUSY;
}
/* usage: tm=0..FFFF cc=0..127 tmin=0/1 tmex=0/1 type=0..10
ftype=0/1 mnr=0..31 idx=%u */
ret = sscanf(buf,
"tm=%X cc=%u tmin=%u tmex=%u type=%u ftype=%u mnr=%u idx=%u",
&tm, &cc, &tmin, &tmex, &type, &ftype, &mnr, &idx);
if (ret < 7) {
/* Not passing index is allowed */
dev_err(dev, "Invalid Trigger Element\n");
pr_err("tm=0..0xFFFF cc=0..127 tmin=0/1 tmex=0/1 type=0..10 ftype=0/1 mnr=0..31 idx=i\n");
return -EINVAL;
}
cur = priv->ttcan->tt_mem_elements;
if ((idx > cur) || (idx == -1))
if (cur >= priv->ttcan->mram_cfg[MRAM_TMC].num) {
dev_err(dev, "Max Invalid Trigger mem Index\n");
return -ENOSPC;
}
if (ret == 8) {
if (idx > cur) {
dev_err(dev, "Invalid Trigger Mem Index\n");
return -EINVAL;
}
/* array access based on user provided index/data */
spec_bar();
ttcan_set_trigger_mem(priv->ttcan, priv->tmc_shadow, idx, tm,
cc, tmin, tmex, type, ftype, mnr);
if (idx == cur)
priv->ttcan->tt_mem_elements++;
} else {
/* array access based on user provided index/data */
spec_bar();
ttcan_set_trigger_mem(priv->ttcan, priv->tmc_shadow, cur, tm,
cc, tmin, tmex, type, ftype, mnr);
priv->ttcan->tt_mem_elements++;
}
return count;
}
static ssize_t show_tdc_offset(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "tdc_offset=0x%x, DBTP.tdc=%d\n",
priv->ttcan->tdc_offset, priv->ttcan->tdc);
}
static ssize_t store_tdc_offset(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct mttcan_priv *priv = netdev_priv(to_net_dev(dev));
unsigned int tdc_offset = 0;
if ((sscanf(buf, "%X", &tdc_offset) != 1)) {
dev_err(dev, "wrong tdc_offset\n");
return -EINVAL;
}
if (tdc_offset != 0)
priv->ttcan->tdc = 1;
else
priv->ttcan->tdc = 0;
priv->ttcan->tdc_offset = tdc_offset;
return count;
}
static DEVICE_ATTR(std_filter, S_IRUGO | S_IWUSR, show_std_fltr,
store_std_fltr);
static DEVICE_ATTR(xtd_filter, S_IRUGO | S_IWUSR, show_xtd_fltr,
store_xtd_fltr);
static DEVICE_ATTR(gfc_filter, S_IRUGO | S_IWUSR, show_gfc_fltr,
store_gfc_fltr);
static DEVICE_ATTR(xidam, S_IRUGO | S_IWUSR, show_xidam, store_xidam);
static DEVICE_ATTR(tx_cancel, S_IRUGO | S_IWUSR, show_tx_cancel,
store_tx_cancel);
static DEVICE_ATTR(ttrmc, S_IRUGO | S_IWUSR, show_ttrmc, store_ttrmc);
static DEVICE_ATTR(ttocf, S_IRUGO | S_IWUSR, show_ttocf, store_ttocf);
static DEVICE_ATTR(ttmlm, S_IRUGO | S_IWUSR, show_ttmlm, store_ttmlm);
static DEVICE_ATTR(tttmc, S_IRUGO | S_IWUSR, show_tttmc, store_tttmc);
static DEVICE_ATTR(txbar, S_IRUGO | S_IWUSR, show_txbar, store_txbar);
static DEVICE_ATTR(cccr_init_txbar, S_IRUGO | S_IWUSR, show_cccr_txbar,
store_cccr_txbar);
static DEVICE_ATTR(trigger_mem, S_IRUGO | S_IWUSR, show_trigger_mem,
store_trigger_mem);
static DEVICE_ATTR(tdc_offset, S_IRUGO | S_IWUSR, show_tdc_offset,
store_tdc_offset);
static struct attribute *mttcan_attr[] = {
&dev_attr_std_filter.attr,
&dev_attr_xtd_filter.attr,
&dev_attr_gfc_filter.attr,
&dev_attr_xidam.attr,
&dev_attr_tx_cancel.attr,
&dev_attr_ttrmc.attr,
&dev_attr_ttocf.attr,
&dev_attr_ttmlm.attr,
&dev_attr_tttmc.attr,
&dev_attr_txbar.attr,
&dev_attr_cccr_init_txbar.attr,
&dev_attr_trigger_mem.attr,
&dev_attr_tdc_offset.attr,
NULL
};
static const struct attribute_group mttcan_attr_group = {
.attrs = mttcan_attr,
};
int mttcan_create_sys_files(struct device *dev)
{
return sysfs_create_group(&dev->kobj, &mttcan_attr_group);
}
void mttcan_delete_sys_files(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &mttcan_attr_group);
}