linux/drivers/ptp/ptp_sysfs.c
<<
>>
Prefs
   1/*
   2 * PTP 1588 clock support - sysfs interface.
   3 *
   4 * Copyright (C) 2010 OMICRON electronics GmbH
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20#include <linux/capability.h>
  21#include <linux/slab.h>
  22
  23#include "ptp_private.h"
  24
  25static ssize_t clock_name_show(struct device *dev,
  26                               struct device_attribute *attr, char *page)
  27{
  28        struct ptp_clock *ptp = dev_get_drvdata(dev);
  29        return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
  30}
  31static DEVICE_ATTR_RO(clock_name);
  32
  33#define PTP_SHOW_INT(name, var)                                         \
  34static ssize_t var##_show(struct device *dev,                           \
  35                           struct device_attribute *attr, char *page)   \
  36{                                                                       \
  37        struct ptp_clock *ptp = dev_get_drvdata(dev);                   \
  38        return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var);     \
  39}                                                                       \
  40static DEVICE_ATTR(name, 0444, var##_show, NULL);
  41
  42PTP_SHOW_INT(max_adjustment, max_adj);
  43PTP_SHOW_INT(n_alarms, n_alarm);
  44PTP_SHOW_INT(n_external_timestamps, n_ext_ts);
  45PTP_SHOW_INT(n_periodic_outputs, n_per_out);
  46PTP_SHOW_INT(n_programmable_pins, n_pins);
  47PTP_SHOW_INT(pps_available, pps);
  48
  49static ssize_t extts_enable_store(struct device *dev,
  50                                  struct device_attribute *attr,
  51                                  const char *buf, size_t count)
  52{
  53        struct ptp_clock *ptp = dev_get_drvdata(dev);
  54        struct ptp_clock_info *ops = ptp->info;
  55        struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS };
  56        int cnt, enable;
  57        int err = -EINVAL;
  58
  59        cnt = sscanf(buf, "%u %d", &req.extts.index, &enable);
  60        if (cnt != 2)
  61                goto out;
  62        if (req.extts.index >= ops->n_ext_ts)
  63                goto out;
  64
  65        err = ops->enable(ops, &req, enable ? 1 : 0);
  66        if (err)
  67                goto out;
  68
  69        return count;
  70out:
  71        return err;
  72}
  73static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
  74
  75static ssize_t extts_fifo_show(struct device *dev,
  76                               struct device_attribute *attr, char *page)
  77{
  78        struct ptp_clock *ptp = dev_get_drvdata(dev);
  79        struct timestamp_event_queue *queue = &ptp->tsevq;
  80        struct ptp_extts_event event;
  81        unsigned long flags;
  82        size_t qcnt;
  83        int cnt = 0;
  84
  85        memset(&event, 0, sizeof(event));
  86
  87        if (mutex_lock_interruptible(&ptp->tsevq_mux))
  88                return -ERESTARTSYS;
  89
  90        spin_lock_irqsave(&queue->lock, flags);
  91        qcnt = queue_cnt(queue);
  92        if (qcnt) {
  93                event = queue->buf[queue->head];
  94                queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
  95        }
  96        spin_unlock_irqrestore(&queue->lock, flags);
  97
  98        if (!qcnt)
  99                goto out;
 100
 101        cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n",
 102                       event.index, event.t.sec, event.t.nsec);
 103out:
 104        mutex_unlock(&ptp->tsevq_mux);
 105        return cnt;
 106}
 107static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
 108
 109static ssize_t period_store(struct device *dev,
 110                            struct device_attribute *attr,
 111                            const char *buf, size_t count)
 112{
 113        struct ptp_clock *ptp = dev_get_drvdata(dev);
 114        struct ptp_clock_info *ops = ptp->info;
 115        struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT };
 116        int cnt, enable, err = -EINVAL;
 117
 118        cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index,
 119                     &req.perout.start.sec, &req.perout.start.nsec,
 120                     &req.perout.period.sec, &req.perout.period.nsec);
 121        if (cnt != 5)
 122                goto out;
 123        if (req.perout.index >= ops->n_per_out)
 124                goto out;
 125
 126        enable = req.perout.period.sec || req.perout.period.nsec;
 127        err = ops->enable(ops, &req, enable);
 128        if (err)
 129                goto out;
 130
 131        return count;
 132out:
 133        return err;
 134}
 135static DEVICE_ATTR(period, 0220, NULL, period_store);
 136
 137static ssize_t pps_enable_store(struct device *dev,
 138                                struct device_attribute *attr,
 139                                const char *buf, size_t count)
 140{
 141        struct ptp_clock *ptp = dev_get_drvdata(dev);
 142        struct ptp_clock_info *ops = ptp->info;
 143        struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
 144        int cnt, enable;
 145        int err = -EINVAL;
 146
 147        if (!capable(CAP_SYS_TIME))
 148                return -EPERM;
 149
 150        cnt = sscanf(buf, "%d", &enable);
 151        if (cnt != 1)
 152                goto out;
 153
 154        err = ops->enable(ops, &req, enable ? 1 : 0);
 155        if (err)
 156                goto out;
 157
 158        return count;
 159out:
 160        return err;
 161}
 162static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
 163
 164static struct attribute *ptp_attrs[] = {
 165        &dev_attr_clock_name.attr,
 166
 167        &dev_attr_max_adjustment.attr,
 168        &dev_attr_n_alarms.attr,
 169        &dev_attr_n_external_timestamps.attr,
 170        &dev_attr_n_periodic_outputs.attr,
 171        &dev_attr_n_programmable_pins.attr,
 172        &dev_attr_pps_available.attr,
 173
 174        &dev_attr_extts_enable.attr,
 175        &dev_attr_fifo.attr,
 176        &dev_attr_period.attr,
 177        &dev_attr_pps_enable.attr,
 178        NULL
 179};
 180
 181static umode_t ptp_is_attribute_visible(struct kobject *kobj,
 182                                        struct attribute *attr, int n)
 183{
 184        struct device *dev = kobj_to_dev(kobj);
 185        struct ptp_clock *ptp = dev_get_drvdata(dev);
 186        struct ptp_clock_info *info = ptp->info;
 187        umode_t mode = attr->mode;
 188
 189        if (attr == &dev_attr_extts_enable.attr ||
 190            attr == &dev_attr_fifo.attr) {
 191                if (!info->n_ext_ts)
 192                        mode = 0;
 193        } else if (attr == &dev_attr_period.attr) {
 194                if (!info->n_per_out)
 195                        mode = 0;
 196        } else if (attr == &dev_attr_pps_enable.attr) {
 197                if (!info->pps)
 198                        mode = 0;
 199        }
 200
 201        return mode;
 202}
 203
 204static const struct attribute_group ptp_group = {
 205        .is_visible     = ptp_is_attribute_visible,
 206        .attrs          = ptp_attrs,
 207};
 208
 209const struct attribute_group *ptp_groups[] = {
 210        &ptp_group,
 211        NULL
 212};
 213
 214static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name)
 215{
 216        int i;
 217        for (i = 0; i < ptp->info->n_pins; i++) {
 218                if (!strcmp(ptp->info->pin_config[i].name, name))
 219                        return i;
 220        }
 221        return -1;
 222}
 223
 224static ssize_t ptp_pin_show(struct device *dev, struct device_attribute *attr,
 225                            char *page)
 226{
 227        struct ptp_clock *ptp = dev_get_drvdata(dev);
 228        unsigned int func, chan;
 229        int index;
 230
 231        index = ptp_pin_name2index(ptp, attr->attr.name);
 232        if (index < 0)
 233                return -EINVAL;
 234
 235        if (mutex_lock_interruptible(&ptp->pincfg_mux))
 236                return -ERESTARTSYS;
 237
 238        func = ptp->info->pin_config[index].func;
 239        chan = ptp->info->pin_config[index].chan;
 240
 241        mutex_unlock(&ptp->pincfg_mux);
 242
 243        return snprintf(page, PAGE_SIZE, "%u %u\n", func, chan);
 244}
 245
 246static ssize_t ptp_pin_store(struct device *dev, struct device_attribute *attr,
 247                             const char *buf, size_t count)
 248{
 249        struct ptp_clock *ptp = dev_get_drvdata(dev);
 250        unsigned int func, chan;
 251        int cnt, err, index;
 252
 253        cnt = sscanf(buf, "%u %u", &func, &chan);
 254        if (cnt != 2)
 255                return -EINVAL;
 256
 257        index = ptp_pin_name2index(ptp, attr->attr.name);
 258        if (index < 0)
 259                return -EINVAL;
 260
 261        if (mutex_lock_interruptible(&ptp->pincfg_mux))
 262                return -ERESTARTSYS;
 263        err = ptp_set_pinfunc(ptp, index, func, chan);
 264        mutex_unlock(&ptp->pincfg_mux);
 265        if (err)
 266                return err;
 267
 268        return count;
 269}
 270
 271int ptp_populate_pin_groups(struct ptp_clock *ptp)
 272{
 273        struct ptp_clock_info *info = ptp->info;
 274        int err = -ENOMEM, i, n_pins = info->n_pins;
 275
 276        if (!n_pins)
 277                return 0;
 278
 279        ptp->pin_dev_attr = kcalloc(n_pins, sizeof(*ptp->pin_dev_attr),
 280                                    GFP_KERNEL);
 281        if (!ptp->pin_dev_attr)
 282                goto no_dev_attr;
 283
 284        ptp->pin_attr = kcalloc(1 + n_pins, sizeof(*ptp->pin_attr), GFP_KERNEL);
 285        if (!ptp->pin_attr)
 286                goto no_pin_attr;
 287
 288        for (i = 0; i < n_pins; i++) {
 289                struct device_attribute *da = &ptp->pin_dev_attr[i];
 290                sysfs_attr_init(&da->attr);
 291                da->attr.name = info->pin_config[i].name;
 292                da->attr.mode = 0644;
 293                da->show = ptp_pin_show;
 294                da->store = ptp_pin_store;
 295                ptp->pin_attr[i] = &da->attr;
 296        }
 297
 298        ptp->pin_attr_group.name = "pins";
 299        ptp->pin_attr_group.attrs = ptp->pin_attr;
 300
 301        ptp->pin_attr_groups[0] = &ptp->pin_attr_group;
 302
 303        return 0;
 304
 305no_pin_attr:
 306        kfree(ptp->pin_dev_attr);
 307no_dev_attr:
 308        return err;
 309}
 310
 311void ptp_cleanup_pin_groups(struct ptp_clock *ptp)
 312{
 313        kfree(ptp->pin_attr);
 314        kfree(ptp->pin_dev_attr);
 315}
 316