Landfall

Annotated pkg/devices/pwm/src/jz4730/pwm-jz4730.cc

0:89a1bc19c1fc
2018-05-13 Paul Boddie Added device libraries and programs, configuration files and examples. Also added an installation script and copyright and licensing information.
paul@0 1
/*
paul@0 2
 * Export a JZ4730 PWM peripheral as a server.
paul@0 3
 *
paul@0 4
 * (c) 2018 Paul Boddie <paul@boddie.org.uk>
paul@0 5
 *
paul@0 6
 * This program is free software; you can redistribute it and/or
paul@0 7
 * modify it under the terms of the GNU General Public License as
paul@0 8
 * published by the Free Software Foundation; either version 2 of
paul@0 9
 * the License, or (at your option) any later version.
paul@0 10
 *
paul@0 11
 * This program is distributed in the hope that it will be useful,
paul@0 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@0 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@0 14
 * GNU General Public License for more details.
paul@0 15
 *
paul@0 16
 * You should have received a copy of the GNU General Public License
paul@0 17
 * along with this program; if not, write to the Free Software
paul@0 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@0 19
 * Boston, MA  02110-1301, USA
paul@0 20
 */
paul@0 21
paul@0 22
#include <l4/devices/gpio-jz4730.h>
paul@0 23
#include <l4/devices/pwm-jz4730.h>
paul@0 24
paul@0 25
#include <l4/cxx/ipc_server>
paul@0 26
#include <l4/re/env>
paul@0 27
#include <l4/re/util/object_registry>
paul@0 28
paul@0 29
#include <stdint.h>
paul@0 30
#include <stdlib.h>
paul@0 31
paul@0 32
#include "pwm-ops.h"
paul@0 33
#include "memory.h"
paul@0 34
paul@0 35
/* Virtual addresses for the GPIO and PWM register blocks. */
paul@0 36
paul@0 37
static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0;
paul@0 38
static l4_addr_t pwm_virt_base = 0, pwm_virt_base_end = 0;
paul@0 39
paul@0 40
paul@0 41
paul@0 42
static int setup_memory(void)
paul@0 43
{
paul@0 44
  if (get_memory("jz4730-gpio", &gpio_virt_base, &gpio_virt_base_end))
paul@0 45
    return 1;
paul@0 46
paul@0 47
  if (get_memory("jz4730-pwm", &pwm_virt_base, &pwm_virt_base_end))
paul@0 48
    return 1;
paul@0 49
paul@0 50
  return 0;
paul@0 51
}
paul@0 52
paul@0 53
paul@0 54
paul@0 55
/* PWM peripheral device. */
paul@0 56
paul@0 57
class Pwm_device_server : public L4::Server_object_t<L4::Kobject>
paul@0 58
{
paul@0 59
  Pwm_jz4730_chip *_device = 0;
paul@0 60
  int _duty, _period, _prescale;
paul@0 61
paul@0 62
public:
paul@0 63
  /* Associate the device with a particular memory region. */
paul@0 64
paul@0 65
  explicit Pwm_device_server(Pwm_jz4730_chip *device, int duty, int period, int prescale)
paul@0 66
  : _device(device), _duty(duty), _period(period), _prescale(prescale)
paul@0 67
  {
paul@0 68
  }
paul@0 69
paul@0 70
  /* Dispatch incoming requests. */
paul@0 71
paul@0 72
  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
paul@0 73
  {
paul@0 74
    l4_msgtag_t tag;
paul@0 75
    int arg;
paul@0 76
paul@0 77
    (void) obj;
paul@0 78
    ios >> tag;
paul@0 79
paul@0 80
    switch (tag.label())
paul@0 81
    {
paul@0 82
      case Pwm_op_disable:
paul@0 83
        disable();
paul@0 84
        return L4_EOK;
paul@0 85
paul@0 86
      case Pwm_op_enable:
paul@0 87
        enable();
paul@0 88
        return L4_EOK;
paul@0 89
paul@0 90
      case Pwm_op_set_control:
paul@0 91
        ios >> arg;
paul@0 92
        set_control(arg);
paul@0 93
        return L4_EOK;
paul@0 94
paul@0 95
      case Pwm_op_set_duty:
paul@0 96
        ios >> arg;
paul@0 97
        set_duty(arg);
paul@0 98
        return L4_EOK;
paul@0 99
paul@0 100
      case Pwm_op_set_period:
paul@0 101
        ios >> arg;
paul@0 102
        set_period(arg);
paul@0 103
        return L4_EOK;
paul@0 104
paul@0 105
      default:
paul@0 106
        return -L4_EBADPROTO;
paul@0 107
    }
paul@0 108
  }
paul@0 109
paul@0 110
  void disable()
paul@0 111
  {
paul@0 112
    _device->disable();
paul@0 113
  }
paul@0 114
paul@0 115
  void enable()
paul@0 116
  {
paul@0 117
    set_duty(_duty);
paul@0 118
    set_period(_period);
paul@0 119
    set_control(0x80 | _prescale); /* enable | prescale */
paul@0 120
  }
paul@0 121
paul@0 122
  /* Set the control register. */
paul@0 123
paul@0 124
  void set_control(uint8_t control)
paul@0 125
  {
paul@0 126
    _device->set_control(control);
paul@0 127
  }
paul@0 128
paul@0 129
  /* Set the PWM duty cycle. */
paul@0 130
paul@0 131
  void set_duty(uint16_t duty)
paul@0 132
  {
paul@0 133
    _duty = duty;
paul@0 134
    _device->set_duty(duty);
paul@0 135
  }
paul@0 136
paul@0 137
  /* Set the PWM period. */
paul@0 138
paul@0 139
  void set_period(uint16_t period)
paul@0 140
  {
paul@0 141
    _period = period;
paul@0 142
    _device->set_period(period);
paul@0 143
  }
paul@0 144
};
paul@0 145
paul@0 146
static L4Re::Util::Registry_server<> server;
paul@0 147
paul@0 148
paul@0 149
paul@0 150
/* Initialise devices and start the server. */
paul@0 151
paul@0 152
static void run(int number, int duty, int period, int prescale)
paul@0 153
{
paul@0 154
  Pwm_jz4730_chip pwm_device(pwm_virt_base + number * 0x1000,
paul@0 155
                             pwm_virt_base + (number + 1) * 0x1000);
paul@0 156
paul@0 157
  Gpio_jz4730_chip gpio_port_c(gpio_virt_base + 2 * 0x30,
paul@0 158
                               gpio_virt_base + 3 * 0x30, 32);
paul@0 159
paul@0 160
  /* Enable the PWM output for PC30 or PC31. */
paul@0 161
paul@0 162
  gpio_port_c.config_pad(30 + number, Hw::Gpio_chip::Function_alt, 1);
paul@0 163
paul@0 164
  /* Initialise and register a new server object. */
paul@0 165
paul@0 166
  Pwm_device_server server_obj(&pwm_device, duty, period, prescale);
paul@0 167
  server.registry()->register_obj(&server_obj, "pwm");
paul@0 168
paul@0 169
  /* Enter the IPC server loop. */
paul@0 170
paul@0 171
  server.loop();
paul@0 172
}
paul@0 173
paul@0 174
paul@0 175
paul@0 176
/* Arguments: <PWM device number> <duty> <period> <prescale> */
paul@0 177
paul@0 178
int main(int argc, char *argv[])
paul@0 179
{
paul@0 180
  int number, duty, period, prescale;
paul@0 181
paul@0 182
  if (argc < 5) return 1;
paul@0 183
paul@0 184
  /* Interpret and restrict the device number. */
paul@0 185
paul@0 186
  number = atoi(argv[1]);
paul@0 187
  if ((number < 0) || (number > 1)) return 1;
paul@0 188
paul@0 189
  /* Interpret and restrict the initial parameters. */
paul@0 190
paul@0 191
  duty = atoi(argv[2]);
paul@0 192
  period = atoi(argv[3]);
paul@0 193
  prescale = atoi(argv[4]);
paul@0 194
  if ((duty < 0) || (period < 0) || (prescale < 0)) return 1;
paul@0 195
paul@0 196
  /* Obtain access to peripheral memory. */
paul@0 197
paul@0 198
  if (setup_memory()) return 1;
paul@0 199
paul@0 200
  run(number, duty, period, prescale);
paul@0 201
  return 0;
paul@0 202
}