<commit_before>/*
 * Copyright (c) 2018 Google LLC.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT apa_apa102

#include <errno.h>
#include <drivers/led_strip.h>
#include <drivers/spi.h>

struct apa102_data {
	struct device *spi;
	struct spi_config cfg;
};

static int apa102_update(struct device *dev, void *buf, size_t size)
{
	struct apa102_data *data = dev->driver_data;
	static const uint8_t zeros[] = {0, 0, 0, 0};
	static const uint8_t ones[] = {0xFF, 0xFF, 0xFF, 0xFF};
	const struct spi_buf tx_bufs[] = {
		{
			/* Start frame: at least 32 zeros */
			.buf = (uint8_t *)zeros,
			.len = sizeof(zeros),
		},
		{
			/* LED data itself */
			.buf = buf,
			.len = size,
		},
		{
			/* End frame: at least 32 ones to clock the
			 * remaining bits to the LEDs at the end of
			 * the strip.
			 */
			.buf = (uint8_t *)ones,
			.len = sizeof(ones),
		},
	};
	const struct spi_buf_set tx = {
		.buffers = tx_bufs,
		.count = ARRAY_SIZE(tx_bufs)
	};

	return spi_write(data->spi, &data->cfg, &tx);
}

static int apa102_update_rgb(struct device *dev, struct led_rgb *pixels,
			     size_t count)
{
	uint8_t *p = (uint8_t *)pixels;
	size_t i;
	/* SOF (3 bits) followed by the 0 to 31 global dimming level */
	uint8_t prefix = 0xE0 | 31;

	/* Rewrite to the on-wire format */
	for (i = 0; i < count; i++) {
		uint8_t r = pixels[i].r;
		uint8_t g = pixels[i].g;
		uint8_t b = pixels[i].b;

		*p++ = prefix;
		*p++ = b;
		*p++ = g;
		*p++ = r;
	}

	BUILD_ASSERT(sizeof(struct led_rgb) == 4);
	return apa102_update(dev, pixels, sizeof(struct led_rgb) * count);
}

static int apa102_update_channels(struct device *dev, uint8_t *channels,
				  size_t num_channels)
{
	/* Not implemented */
	return -EINVAL;
}

static int apa102_init(struct device *dev)
{
	struct apa102_data *data = dev->driver_data;

	data->spi = device_get_binding(DT_INST_BUS_LABEL(0));
	if (!data->spi) {
		return -ENODEV;
	}

	data->cfg.slave = DT_INST_REG_ADDR(0);
	data->cfg.frequency = DT_INST_PROP(0, spi_max_frequency);
	data->cfg.operation =
		SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8);

	return 0;
}

static struct apa102_data apa102_data_0;
<commit_msg>drivers: led_strip: Add support for external SPI CS on APA102 LED strips<commit_after>/*
 * Copyright (c) 2018 Google LLC.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT apa_apa102

#include <errno.h>
#include <drivers/led_strip.h>
#include <drivers/spi.h>
#include <drivers/gpio.h>
#include <sys/util.h>

/*
 * Devicetree helper macros which gets the 'flags' cell from a 'cs_gpios'
 * property on the spi bus, or returns 0 if the property has no 'flags' cell.
 *
 * Hopefully these helpers will be removed once #25827 is resolved.
 */
#define HAS_FLAGS(spi_dev, spi_reg)					\
	DT_PHA_HAS_CELL_AT_IDX(spi_dev, cs_gpios, spi_reg, flags)

#define INST_SPI_DEV_CS_GPIOS_HAS_FLAGS(node)			\
	HAS_FLAGS(DT_BUS(node), DT_REG_ADDR(node))

#define FLAGS_OR_ZERO(inst)						\
	COND_CODE_1(							\
		INST_SPI_DEV_CS_GPIOS_HAS_FLAGS(DT_DRV_INST(inst)),	\
		(DT_INST_SPI_DEV_CS_GPIOS_FLAGS(inst)),			\
		(0x0))

struct apa102_data {
	struct device *spi;
	struct spi_config cfg;
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
	struct spi_cs_control cs_ctl;
#endif /* DT_INST_SPI_DEV_HAS_CS_GPIOS(0) */
};

static int apa102_update(struct device *dev, void *buf, size_t size)
{
	struct apa102_data *data = dev->driver_data;
	static const uint8_t zeros[] = {0, 0, 0, 0};
	static const uint8_t ones[] = {0xFF, 0xFF, 0xFF, 0xFF};
	const struct spi_buf tx_bufs[] = {
		{
			/* Start frame: at least 32 zeros */
			.buf = (uint8_t *)zeros,
			.len = sizeof(zeros),
		},
		{
			/* LED data itself */
			.buf = buf,
			.len = size,
		},
		{
			/* End frame: at least 32 ones to clock the
			 * remaining bits to the LEDs at the end of
			 * the strip.
			 */
			.buf = (uint8_t *)ones,
			.len = sizeof(ones),
		},
	};
	const struct spi_buf_set tx = {
		.buffers = tx_bufs,
		.count = ARRAY_SIZE(tx_bufs)
	};

	return spi_write(data->spi, &data->cfg, &tx);
}

static int apa102_update_rgb(struct device *dev, struct led_rgb *pixels,
			     size_t count)
{
	uint8_t *p = (uint8_t *)pixels;
	size_t i;
	/* SOF (3 bits) followed by the 0 to 31 global dimming level */
	uint8_t prefix = 0xE0 | 31;

	/* Rewrite to the on-wire format */
	for (i = 0; i < count; i++) {
		uint8_t r = pixels[i].r;
		uint8_t g = pixels[i].g;
		uint8_t b = pixels[i].b;

		*p++ = prefix;
		*p++ = b;
		*p++ = g;
		*p++ = r;
	}

	BUILD_ASSERT(sizeof(struct led_rgb) == 4);
	return apa102_update(dev, pixels, sizeof(struct led_rgb) * count);
}

static int apa102_update_channels(struct device *dev, uint8_t *channels,
				  size_t num_channels)
{
	/* Not implemented */
	return -EINVAL;
}

static int apa102_init(struct device *dev)
{
	struct apa102_data *data = dev->driver_data;

	data->spi = device_get_binding(DT_INST_BUS_LABEL(0));
	if (!data->spi) {
		return -ENODEV;
	}

	data->cfg.slave = DT_INST_REG_ADDR(0);
	data->cfg.frequency = DT_INST_PROP(0, spi_max_frequency);
	data->cfg.operation =
		SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8);

#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
	data->cs_ctl.gpio_dev =
		device_get_binding(DT_INST_SPI_DEV_CS_GPIOS_LABEL(0));
	if (!data->cs_ctl.gpio_dev) {
		return -ENODEV;
	}
	data->cs_ctl.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(0);
	data->cs_ctl.delay = 0;

	data->cfg.cs = &data->cs_ctl;

	gpio_pin_configure(data->cs_ctl.gpio_dev, data->cs_ctl.gpio_pin,
			   GPIO_OUTPUT_INACTIVE | FLAGS_OR_ZERO(0));
#endif /* DT_INST_SPI_DEV_HAS_CS_GPIOS(0) */

	return 0;
}

static struct apa102_data apa102_data_0;

{'fraction_non_alphanumeric': 0.1362904668216777, 'fraction_numerical': 0.031479162940439995, 'mean_word_length': 3.722972972972973, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2981100', 'n_tokens_mistral': 2561, 'n_tokens_neox': 2310, 'n_words': 545}