blob: 6371c3f2e739121cc8323928f5479aea89de9ef9 [file]
/* SPDX-License-Identifier: LGPL-2.1 */
/* SPDX-FileCopyrightText: 2023 Uwe Kleine-König <u.kleine-koenig@pengutronix.de> */
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <linux/pwm.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <pwm.h>
#include "pwm-internal.h"
struct pwm_cdev {
struct pwm pwm;
unsigned int hwpwm;
};
struct pwm_chip_cdev {
struct pwm_chip chip;
int fd;
struct pwm_cdev *pwms[];
};
static void pwm_chip_cdev_close(struct pwm_chip *chip)
{
struct pwm_chip_cdev *chip_cdev = container_of(chip, struct pwm_chip_cdev, chip);
close(chip_cdev->fd);
free(chip_cdev);
}
static struct pwm *pwm_chip_cdev_get_pwm(struct pwm_chip *chip,
unsigned int offset)
{
struct pwm_chip_cdev *chip_cdev = container_of(chip, struct pwm_chip_cdev, chip);
struct pwm_cdev *pwm_cdev;
struct pwm *pwm;
if (chip_cdev->pwms[offset])
return &chip_cdev->pwms[offset]->pwm;
pwm_cdev = calloc(1, sizeof(*pwm_cdev));
if (!pwm_cdev)
return NULL;
pwm = &pwm_cdev->pwm;
pwm->chip = chip;
pwm_cdev->hwpwm = offset;
return pwm;
}
static int pwm_chip_cdev_apply_state(struct pwm *pwm,
const struct pwm_state *state)
{
struct pwm_cdev *pwm_cdev = container_of(pwm, struct pwm_cdev, pwm);
struct pwm_chip_cdev *chip_cdev = container_of(pwm->chip, struct pwm_chip_cdev, chip);
const struct pwmchip_state s = {
.hwpwm = pwm_cdev->hwpwm,
.period = state->period,
.duty_cycle = state->duty_cycle,
.duty_offset = state->duty_offset,
};
return ioctl(chip_cdev->fd, PWM_IOCTL_APPLY, &s);
}
static int pwm_chip_cdev_get_state(struct pwm *pwm, struct pwm_state *state)
{
errno = EIO;
return -1;
}
struct pwm_chip *pwm_chip_cdev_open_by_number(unsigned int num)
{
struct pwm_chip_cdev *chip_cdev;
struct pwm_chip *chip;
int fd;
ssize_t ret;
unsigned long npwm;
char buf[128];
ret = snprintf(buf, sizeof(buf), "/dev/pwmchip%d", num);
if (ret < 0)
return NULL;
if (ret >= sizeof(buf)) {
/* huh */
errno = EINVAL;
return NULL;
}
fd = open(buf, O_RDWR | O_CLOEXEC);
if (fd < 0)
return NULL;
ret = ioctl(fd, PWM_IOCTL_GET_NUM_PWMS);
if (ret < 0) {
close(fd);
return NULL;
}
npwm = ret;
chip_cdev = calloc(1, sizeof(*chip_cdev) + npwm * sizeof(chip_cdev->pwms[0]));
if (!chip_cdev) {
close(fd);
return NULL;
}
chip = &chip_cdev->chip;
chip->close = pwm_chip_cdev_close;
chip->get_pwm = pwm_chip_cdev_get_pwm;
chip->apply_state = pwm_chip_cdev_apply_state;
chip->get_state = pwm_chip_cdev_get_state;
chip->npwm = npwm;
chip_cdev->fd = fd;
return chip;
}