1 /* 2 * Pulse width modulation peripheral support. 3 * 4 * (c) 2018 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (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., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/hw_mmio_register_block.h> 23 #include "pwm-jz4730.h" 24 25 26 27 enum Regs : unsigned 28 { 29 Pwm_control = 0x000, // CTR 30 Pwm_period = 0x004, // PER 31 Pwm_duty = 0x008, // DUT 32 }; 33 34 enum Control_bits : unsigned 35 { 36 Pwm_enable = 7, 37 Pwm_abrupt_shutdown = 6, 38 Pwm_prescale_mask = 0x3f, 39 }; 40 41 enum Duty_bits : unsigned 42 { 43 Pwm_duty_full = 10, 44 Pwm_duty_mask = 0x3ff, 45 }; 46 47 enum Period_bits : unsigned 48 { 49 Pwm_period_mask = 0x3ff, 50 }; 51 52 53 54 // If implemented as a Hw::Device, various properties would be 55 // initialised in the constructor and obtained from the device tree 56 // definitions. 57 58 Pwm_jz4730_chip::Pwm_jz4730_chip(l4_addr_t start, l4_addr_t end) 59 : _start(start), _end(end) 60 { 61 _regs = new Hw::Mmio_register_block<32>(_start); 62 63 // add_cid("pwm"); 64 // add_cid("pwm-jz4730"); 65 } 66 67 void 68 Pwm_jz4730_chip::set_control(uint8_t control) 69 { 70 // This allows the setting of the actual control bits. 71 72 _regs[Pwm_control] = control; 73 } 74 75 void 76 Pwm_jz4730_chip::disable() 77 { 78 _regs[Pwm_control] = _regs[Pwm_control] & ~(1 << Pwm_enable); 79 } 80 81 void 82 Pwm_jz4730_chip::enable() 83 { 84 _regs[Pwm_control] = _regs[Pwm_control] | (1 << Pwm_enable); 85 } 86 87 void 88 Pwm_jz4730_chip::set_shutdown_mode(enum Jz4730_pwm_shutdown_mode mode) 89 { 90 if (mode == Jz4730_pwm_shutdown_graceful) 91 _regs[Pwm_control] = _regs[Pwm_control] & ~(1 << Pwm_abrupt_shutdown); 92 else 93 _regs[Pwm_control] = _regs[Pwm_control] | (1 << Pwm_abrupt_shutdown); 94 } 95 96 void 97 Pwm_jz4730_chip::set_duty(uint16_t duty) 98 { 99 // This deselects full duty, if it were set. 100 // NOTE: A way of selecting full duty is required. 101 102 _regs[Pwm_duty] = (_regs[Pwm_duty] & ~(Pwm_duty_mask | (1 << Pwm_duty_full))) | 103 (duty & Pwm_duty_mask); 104 } 105 106 void 107 Pwm_jz4730_chip::set_period(uint16_t period) 108 { 109 _regs[Pwm_period] = (_regs[Pwm_period] & ~Pwm_period_mask) | 110 (period & Pwm_period_mask); 111 } 112 113 114 115 116 // C language interface functions. 117 118 void * 119 jz4730_pwm_init(l4_addr_t start, l4_addr_t end) 120 { 121 return (void *) new Pwm_jz4730_chip(start, end); 122 } 123 124 void 125 jz4730_pwm_disable(void *pwm) 126 { 127 static_cast<Pwm_jz4730_chip *>(pwm)->disable(); 128 } 129 130 void 131 jz4730_pwm_enable(void *pwm) 132 { 133 static_cast<Pwm_jz4730_chip *>(pwm)->enable(); 134 } 135 136 void 137 jz4730_pwm_set_shutdown_mode(void *pwm, enum Jz4730_pwm_shutdown_mode mode) 138 { 139 static_cast<Pwm_jz4730_chip *>(pwm)->set_shutdown_mode(mode); 140 } 141 142 void 143 jz4730_pwm_set_control(void *pwm, uint8_t control) 144 { 145 static_cast<Pwm_jz4730_chip *>(pwm)->set_control(control); 146 } 147 148 void 149 jz4730_pwm_set_duty(void *pwm, uint16_t duty) 150 { 151 static_cast<Pwm_jz4730_chip *>(pwm)->set_duty(duty); 152 } 153 154 void 155 jz4730_pwm_set_period(void *pwm, uint16_t period) 156 { 157 static_cast<Pwm_jz4730_chip *>(pwm)->set_period(period); 158 }