IMGJulian closed pull request #630: LP5523: LED Driver
URL: https://github.com/apache/mynewt-core/pull/630
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/hw/drivers/lp5523/include/lp5523/lp5523.h 
b/hw/drivers/lp5523/include/lp5523/lp5523.h
new file mode 100644
index 000000000..0b8a758a9
--- /dev/null
+++ b/hw/drivers/lp5523/include/lp5523/lp5523.h
@@ -0,0 +1,1256 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __LP5523_H__
+#define __LP5523_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sensor/sensor.h>
+
+#define LP5523_I2C_BASE_ADDR (0x32)
+
+/* Engine control mask */
+#define LP5523_ENGINE3_MASK (0x03)
+#define LP5523_ENGINE2_MASK (0x0c)
+#define LP5523_ENGINE1_MASK (0x30)
+
+/* Engine IDs */
+#define LP5523_ENGINE3 (3)
+#define LP5523_ENGINE2 (2)
+#define LP5523_ENGINE1 (1)
+
+/* LED IDs */
+#define LP5523_LED9 (9)
+#define LP5523_LED8 (8)
+#define LP5523_LED7 (7)
+#define LP5523_LED6 (6)
+#define LP5523_LED5 (5)
+#define LP5523_LED4 (4)
+#define LP5523_LED3 (3)
+#define LP5523_LED2 (2)
+#define LP5523_LED1 (1)
+
+struct lp5523_cfg {
+    /* The 2 LSBs of this represent ASEL1 and ASEL0 */
+    uint8_t asel;
+    uint8_t clk_det_en;
+    uint8_t int_clk_en;
+    uint8_t cp_mode;
+    uint8_t int_conf;
+};
+
+struct lp5523 {
+    struct os_dev dev;
+    struct sensor sensor;
+    struct lp5523_cfg cfg;
+};
+
+/* register addresses */
+
+enum lp5523_bitfield_registers {
+    LP5523_OUTPUT_RATIOMETRIC = 0x02,
+    LP5523_OUTPUT_CONTROL = 0x04,
+    LP5523_ENG_MAPPING = 0x70
+};
+
+enum lp5523_output_registers {
+    LP5523_CONTROL = 0x06,
+    LP5523_PWM = 0x16,
+    LP5523_CURRENT_CONTROL = 0x26
+};
+
+enum lp5523_engine_registers {
+    LP5523_ENGINE_PC = 0x37,
+    LP5523_ENGINE_VARIABLE_A = 0x45,
+    LP5523_MASTER_FADER = 0x48,
+    LP5523_ENG_PROG_START_ADDR = 0x4c
+};
+
+enum lp5523_engine_control_registers {
+    LP5523_ENGINE_CNTRL1 = 0x00,
+    LP5523_ENGINE_CNTRL2 = 0x01
+};
+
+enum lp5523_registers {
+    LP5523_ENABLE = 0x00,
+    LP5523_MISC = 0x36,
+    LP5523_STATUS = 0x3a,
+    LP5523_INTERRUPT = 0x3a,
+    LP5523_INT = 0x3b,
+    LP5523_VARIABLE = 0x3c,
+    LP5523_RESET = 0x3d,
+    LP5523_TEMP_ADC_CONTROL = 0x3e,
+    LP5523_TEMPERATURE_READ = 0x3f,
+    LP5523_TEMPERATURE_WRITE = 0x40,
+    LP5523_LED_TEST_CONTROL = 0x41,
+    LP5523_LED_TEST_ADC = 0x42,
+    LP5523_PROG_MEM_PAGE_SEL = 0x4f,
+    LP5523_PROGRAM_MEMORY = 0x50,
+    LP5523_GAIN_CHANGE_CTRL = 0x76
+};
+
+/* registers */
+struct lp5523_register_value {
+    uint8_t reg;
+    uint8_t pos;
+    uint8_t mask;
+};
+
+#define LP5523_REGISTER_VALUE(r, n, p, m) \
+static const struct lp5523_register_value n = { .reg = r, .pos = p, .mask = m }
+
+/* control1 */
+LP5523_REGISTER_VALUE(LP5523_ENABLE, LP5523_CHIP_EN, 6, 0x40);
+
+#define LP5523_ENGINES_HOLD (0x00)
+#define LP5523_ENGINES_STEP (0x15)
+#define LP5523_ENGINES_FREE_RUN (0x2a)
+#define LP5523_ENGINES_EXECUTE_ONCE (0x3f)
+
+/* control2 */
+#define LP5523_ENGINES_DISABLED (0x00)
+#define LP5523_ENGINES_LOAD_PROGRAM (0x15)
+#define LP5523_ENGINES_RUN_PROGRAM (0x2a)
+#define LP5523_ENGINES_HALT (0x3f)
+
+/* output control */
+LP5523_REGISTER_VALUE(LP5523_CONTROL, LP5523_OUTPUT_MAPPING, 6, 0xc0);
+LP5523_REGISTER_VALUE(LP5523_CONTROL, LP5523_OUTPUT_LOG_EN, 5, 0x20);
+LP5523_REGISTER_VALUE(LP5523_CONTROL, LP5523_OUTPUT_TEMP_COMP, 0, 0x1f);
+
+/* misc */
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_VARIABLE_D_SEL, 7, 0x80);
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_EN_AUTO_INCR, 6, 0x40);
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_POWERSAVE_EN, 5, 0x20);
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_CP_MODE, 3, 0x18);
+
+#define LP5523_CP_OFF (0x00)
+#define LP5523_CP_FORCED_BYPASS (0x01)
+#define LP5523_CP_FORCED_BOOST (0x02)
+#define LP5523_CP_AUTOMATIC (0x03)
+
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_PWM_PS_EN, 2, 0x04);
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_CLK_DET_EN, 1, 0x02);
+LP5523_REGISTER_VALUE(LP5523_MISC, LP5523_INT_CLK_EN, 0, 0x01);
+
+/* status */
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_MEAS_DONE, 7, 0x80);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_MASK_BUSY, 6, 0x40);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_STARTUP_BUSY, 5, 0x20);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_ENGINE_BUSY, 4, 0x10);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_EXT_CLK_USED, 3, 0x08);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_ENG1_INT, 2, 0x04);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_ENG2_INT, 1, 0x02);
+LP5523_REGISTER_VALUE(LP5523_STATUS, LP5523_ENG3_INT, 0, 0x01);
+
+/* INT */
+LP5523_REGISTER_VALUE(LP5523_INT, LP5523_INT_CONF, 2, 0x04);
+LP5523_REGISTER_VALUE(LP5523_INT, LP5523_INT_GPO, 0, 0x01);
+
+/* temp ADC control */
+LP5523_REGISTER_VALUE(LP5523_TEMP_ADC_CONTROL, LP5523_TEMP_MEAS_BUSY, 7, 0x80);
+LP5523_REGISTER_VALUE(LP5523_TEMP_ADC_CONTROL, LP5523_EN_TEMP_SENSOR, 2, 0x04);
+LP5523_REGISTER_VALUE(LP5523_TEMP_ADC_CONTROL, LP5523_TEMP_CONTINUOUS_CONV, 1,
+    0x02);
+LP5523_REGISTER_VALUE(LP5523_TEMP_ADC_CONTROL, LP5523_SEL_EXT_TEMP, 0, 0x01);
+
+/* LED test control */
+LP5523_REGISTER_VALUE(LP5523_LED_TEST_CONTROL, LP5523_EN_LED_TEST_ADC, 7, 
0x80);
+LP5523_REGISTER_VALUE(LP5523_LED_TEST_CONTROL, LP5523_EN_LED_TEST_INT, 6, 
0x40);
+LP5523_REGISTER_VALUE(LP5523_LED_TEST_CONTROL, LP5523_LED_CONTINUOUS_CONV, 5,
+    0x20);
+LP5523_REGISTER_VALUE(LP5523_LED_TEST_CONTROL, LP5523_LED_LED_TEST, 0, 0x1f);
+
+#define LP5523_LED_TEST_D1 (0x00)
+#define LP5523_LED_TEST_D2 (0x01)
+#define LP5523_LED_TEST_D3 (0x02)
+#define LP5523_LED_TEST_D4 (0x03)
+#define LP5523_LED_TEST_D5 (0x04)
+#define LP5523_LED_TEST_D6 (0x05)
+#define LP5523_LED_TEST_D7 (0x06)
+#define LP5523_LED_TEST_D8 (0x07)
+#define LP5523_LED_TEST_D9 (0x08)
+#define LP5523_LED_TEST_VOUT (0x0f)
+#define LP5523_LED_TEST_VDD (0x10)
+#define LP5523_LED_TEST_INT (0x11)
+
+#define LP5523_LED_TEST_SC_LIM (80)
+
+/* program memory */
+#define LP5523_PAGE_SIZE (0x10)
+#define LP5523_MEMORY_SIZE (LP5523_PAGE_SIZE * 6)
+
+/* gain change ctrl */
+LP5523_REGISTER_VALUE(LP5523_GAIN_CHANGE_CTRL, LP5523_THRESHOLD_MASK, 6, 0xc0);
+LP5523_REGISTER_VALUE(LP5523_GAIN_CHANGE_CTRL, LP5523_ADAPTIVE_THRESH_EN, 5,
+    0x20);
+LP5523_REGISTER_VALUE(LP5523_GAIN_CHANGE_CTRL, LP5523_TIMER, 3, 0x18);
+LP5523_REGISTER_VALUE(LP5523_GAIN_CHANGE_CTRL, LP5523_FORCE_1X, 2, 0x04);
+
+/**
+ * Writes a single byte to the specified register.
+ *
+ * @param The sensor interface.
+ * @param The register address to write to.
+ * @param The value to write.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_reg(struct sensor_itf *itf, enum lp5523_registers addr,
+    uint8_t value);
+
+/**
+ * Reads a single byte from the specified register.
+ *
+ * @param The sensor interface.
+ * @param The register address to read from.
+ * @param Pointer to where the register value should be written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_reg(struct sensor_itf *itf, enum lp5523_registers addr,
+    uint8_t *value);
+
+/**
+ * Applies a value to a position in a local register value.
+ *
+ * @param A struct containing the position and mask to use for the write.
+ * @param The value to write.
+ * @param Pointer to register to be modified.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_apply_value(struct lp5523_register_value addr, uint8_t value,
+        uint8_t *reg);
+
+/**
+ * Writes a section of the specified register.
+ *
+ * @param The sensor interface.
+ * @param The register address to write to.
+ * @param The mask.
+ * @param Value to write.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_value(struct sensor_itf *itf, struct lp5523_register_value addr,
+    uint8_t value);
+
+/**
+ * Reads a section from the specified register.
+ *
+ * @param The sensor interface.
+ * @param The register address to read from.
+ * @param The mask.
+ * @param Pointer to where the value should be written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_value(struct sensor_itf *itf, struct lp5523_register_value addr,
+    uint8_t *value);
+
+/**
+ * Writes 9 bits to 2 registers.
+ * To write to:
+ * LP5523_BF_OUTPUT_RATIOMETRIC
+ * LP5523_BF_OUTPUT_CONTROL
+ * LP5523_BF_ENG_MAPPING (see lp5523_set_engine_mapping())
+ *
+ * @param The sensor interface.
+ * @param The register address to write to (the MSB register).
+ * @param The values to write, only the least significant 9 bits are
+ * significant.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_bitfield(struct sensor_itf *itf,
+    enum lp5523_bitfield_registers addr, uint16_t outputs);
+
+/**
+ * Writes 9 bits to 2 registers.
+ * To read from:
+ * LP5523_BF_OUTPUT_RATIOMETRIC
+ * LP5523_BF_OUTPUT_CONTROL
+ * LP5523_BF_ENG_MAPPING (see lp5523_set_engine_mapping())
+ *
+ * @param The sensor interface.
+ * @param The register address to read from (the MSB register).
+ * @param Pointer to where the register values should be written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_bitfield(struct sensor_itf *itf,
+    enum lp5523_bitfield_registers addr, uint16_t* outputs);
+
+/**
+ * Writes to a register with an output-based address offset.
+ * To write to:
+ * LP5523_CONTROL
+ * LP5523_PWM
+ * LP5523_CURRENT_CONTROL
+ *
+ * @param The sensor interface.
+ * @param The register address to write to (the MSB register).
+ * @param Output ID 1-9.
+ * @param Value to write.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_output_reg(struct sensor_itf *itf,
+    enum lp5523_output_registers addr, uint8_t output, uint8_t value);
+
+/**
+ * Reads from a register with an output-based address offset.
+ * To read from:
+ * LP5523_CONTROL
+ * LP5523_PWM
+ * LP5523_CURRENT_CONTROL
+ *
+ * @param The sensor interface.
+ * @param The register address to read from (the MSB register).
+ * @param Output ID 1-9.
+ * @param Pointer to where the register values should be written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_output_reg(struct sensor_itf *itf,
+    enum lp5523_output_registers addr, uint8_t output, uint8_t *value);
+
+/**
+ * Writes to a register with an engine-based address offset.
+ * To write to:
+ * LP5523_ENGINE_PC
+ * LP5523_ENG_PROG_START_ADDR
+ * LP5523_MASTER_FADER
+ *
+ * @param The sensor interface.
+ * @param The register address to write to (the MSB register).
+ * @param Engine ID 1-3.
+ * @param Value to write.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_engine_reg(struct sensor_itf *itf,
+    enum lp5523_engine_registers addr, uint8_t engine, uint8_t value);
+
+/**
+ * Reads from a register with an engine-based address offset.
+ * To read from:
+ * LP5523_ENGINE_PC
+ * LP5523_ENG_PROG_START_ADDR
+ * LP5523_MASTER_FADER
+ *
+ * @param The sensor interface.
+ * @param The register address to read from (the MSB register).
+ * @param Engine ID 1-3.
+ * @param Pointer to where the register values should be written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_engine_reg(struct sensor_itf *itf,
+    enum lp5523_engine_registers addr, uint8_t engine, uint8_t *value);
+
+/**
+ * Sets the CHIP_EN bit in the ENABLE register.
+ *
+ * @param The sensor interface.
+ * @param Non 0 to enable the device, 0 to disable it.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_enable(struct sensor_itf *itf, uint8_t enable);
+
+/**
+ * Sets the ENGINEX_MODE and ENGINEX_EXEC bits in the ENGINE CNTRLX registers.
+ *
+ * @param The sensor interface struct.
+ * @param Control register to update: LP5523_ENGINE_CNTRL1 or
+ *  LP5523_ENGINE_CNTRL2.
+ * @param Engines to update, a combination of LP5523_ENGINE3_MASK,
+ *  LP5523_ENGINE2_MASK or LP5523_ENGINE1_MASK.
+ * @param Values to write, the lower 6 bits are relavant, 2 per engine.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_engine_control(struct sensor_itf *itf,
+    enum lp5523_engine_control_registers addr, uint8_t engine_mask,
+    uint8_t values);
+
+/**
+ * Sets the MAPPING bits in the relevant DX CONTROL register.
+ *
+ * @param The sensor interface struct.
+ * @param Output number 1-9.
+ * @param Mapping 0-3.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_output_mapping(struct sensor_itf *itf, uint8_t output,
+    uint8_t mapping);
+
+/**
+ * Gets the MAPPING bits from the relevant DX CONTROL register.
+ *
+ * @param The sensor interface struct.
+ * @param Output number 1-9.
+ * @param Pointer to where the output mapping (0-3) should be written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_output_mapping(struct sensor_itf *itf, uint8_t output,
+    uint8_t *mapping);
+
+/**
+ * Sets the LOG_EN bit in the relevant DX CONTROL register.
+ *
+ * @param The sensor interface struct.
+ * @param Output number 1-9.
+ * @param Non 0 to enable logarithmic dimming, 0 to disable it.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_output_log_dim(struct sensor_itf *itf, uint8_t output,
+    uint8_t enable);
+
+/**
+ * Gets the LOG_EN bit grom the relevant DX CONTROL register.
+ *
+ * @param The sensor interface struct.
+ * @param Output number 1-9.
+ * @param Written to 1 if logarithmic dimming is enabled, 0 if it is disabled.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_output_log_dim(struct sensor_itf *itf, uint8_t output,
+    uint8_t *enable);
+
+/**
+ * Sets the TEMP_COMP bits in the relevant DX CONTROL register.
+ *
+ * @param The sensor interface struct.
+ * @param Output number 1-9.
+ * @param Temperature compensation value.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_output_temp_comp(struct sensor_itf *itf, uint8_t output,
+    uint8_t value);
+
+/**
+ * Gets the TEMP_COMP bits from the relevant DX CONTROL register.
+ *
+ * @param The sensor interface struct.
+ * @param Output number 1-9.
+ * @param Pointer to where the temperature compensation value should be 
written.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_output_temp_comp(struct sensor_itf *itf, uint8_t output,
+    uint8_t *value);
+
+/**
+ * Gets the relevant ENGX_INT bit from the status register.
+ *
+ * @param The sensor interface struct.
+ * @param Engine number 1-3.
+ * @param Written to the value of the bit.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_engine_int(struct sensor_itf *itf, uint8_t engine,
+    uint8_t *flag);
+
+/**
+ * Resets the device.
+ *
+ * @param The sensor interface.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_reset(struct sensor_itf *itf);
+
+/**
+ * Sets the page used for program memory reads and writes.
+ *
+ * @param The sensor interface struct.
+ * @param The page 0-5.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_page_sel(struct sensor_itf *itf, uint8_t page);
+
+/**
+ * Sets or clears the relevant DX bit in the ENGX MAPPING registers.
+ *
+ * @param The sensor interface.
+ * @param ID of the engine 1-3.
+ * @param Output number 1-9.
+ * @param Non 0 to map the output to the specified engine, 0 to unmap it.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_engine_mapping(struct sensor_itf *itf, uint8_t engine,
+    uint16_t output);
+
+/**
+ * Gets the relevant DX bit from the ENGX MAPPING registers.
+ *
+ * @param The sensor interface.
+ * @param ID of the engine 1-3.
+ * @param Output number 1-9.
+ * @param Written to 1 if the output is mapped to the specified engine, 0 if it
+ * is not mapped to that engine.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_engine_mapping(struct sensor_itf *itf, uint8_t engine,
+    uint16_t *output);
+
+/**
+ * Sets an instruction in program memory.
+ *
+ * @param The sensor interface struct.
+ * @param Address to write to.
+ * @param Instruction to write.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_instruction(struct sensor_itf *itf, uint8_t addr, uint16_t ins);
+
+/**
+ * gets an instruction from program memory.
+ *
+ * @param The sensor interface struct.
+ * @param Address to read from.
+ * @param Written to the instruction.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_instruction(struct sensor_itf *itf, uint8_t addr, uint16_t 
*ins);
+
+/**
+ * Writes a program to memory.
+ *
+ * @param The sensor interface struct.
+ * @param Engines to reset, a combination of LP5523_ENGINE3, LP5523_ENGINE2
+ *  or LP5523_ENGINE1.
+ * @param Program to write.
+ * @param Address to start writing the program.
+ * @param Write size.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_set_program(struct sensor_itf *itf, uint8_t engines, uint16_t *pgm,
+    uint8_t start, uint8_t size);
+
+/**
+ * Reads a program from memory.
+ *
+ * @param The sensor interface struct.
+ * @param Buffer to read into.
+ * @param Address to start reading the program.
+ * @param read size.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_get_program(struct sensor_itf *itf, uint16_t *pgm, uint8_t start,
+    uint8_t size);
+
+/**
+ * Reads a program from memory and compares it to one passed in as an arg.
+ *
+ * @param The sensor interface struct.
+ * @param Program to verify against.
+ * @param Address to start reading the program.
+ * @param read size.
+ *
+ * @return 0 on success, 1 on verify failure, other non-zero error on other
+ * failure.
+ */
+int lp5523_verify_program(struct sensor_itf *itf, uint16_t *pgm, uint8_t start,
+    uint8_t size);
+
+/**
+ * Sets the specified engines to execute their respective programs.
+ *
+ * @param The sensor interface struct.
+ * @param Engines to run, a combination of LP5523_ENGINE3, LP5523_ENGINE2
+ *  or LP5523_ENGINE1.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_engines_run(struct sensor_itf *itf, uint8_t engines);
+
+/**
+ * Sets the specified engines to hold execution of their respective programs.
+ *
+ * @param The sensor interface struct.
+ * @param Engines to run, a combination of LP5523_ENGINE3, LP5523_ENGINE2
+ *  or LP5523_ENGINE1.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_engines_hold(struct sensor_itf *itf, uint8_t engines);
+
+/**
+ * Sets the specified engines to execute the next instruction of their
+ * respective programs and increment their PCs.
+ *
+ * @param The sensor interface struct.
+ * @param Engines to run, a combination of LP5523_ENGINE3, LP5523_ENGINE2
+ *  or LP5523_ENGINE1.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_engines_step(struct sensor_itf *itf, uint8_t engines);
+
+/**
+ * Disables the specified engines.
+ *
+ * @param The sensor interface struct.
+ * @param Engines to run, a combination of LP5523_ENGINE3, LP5523_ENGINE2
+ *  or LP5523_ENGINE1.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_engines_disable(struct sensor_itf *itf, uint8_t engines);
+
+/**
+ * Reads the ADC on a pin.
+ *
+ * @param The sensor interface struct.
+ * @param Pin to read.
+ * @param Written to the voltage.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_read_adc(struct sensor_itf *itf, uint8_t pin, uint8_t *v);
+
+/**
+ * Tests the Device, checks for a clock if necessary and checks the ADC values
+ * for each LED pin are reasonable.
+ *
+ * @param The sensor interface struct.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_self_test(struct sensor_itf *itf);
+
+/**
+ * Expects to be called back through os_dev_create().
+ *
+ * @param The device object associated with this LED driver.
+ * @param Argument passed to OS device init, unused.
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int lp5523_init(struct os_dev *dev, void *arg);
+int lp5523_config(struct lp5523 *lp, struct lp5523_cfg *cfg);
+
+#if MYNEWT_VAL(LP5523_CLI)
+int lp5523_shell_init(void);
+#endif
+
+/* instructions
+ *
+ * programs look like:
+ *
+ * uint16_t pgm[] = {
+ *   LP5523_INS_RAMP_IM(1, 1, 0, 100),
+ *   LP5523_INS_SET_PWM_IM(50),
+ *   ...
+ *   LP5523_INS_MUX_MAP_ADDR(24)
+ * };
+ *
+ * loaded with:
+ *
+ * lp5523_program_load(sensor, engine, pgm, sizeof(pgm)/sizeof(*pgm));
+ */
+
+/* sign */
+
+#define LP5523_POS (0)
+#define LP5523_NEG (1)
+
+/* prescaler */
+
+#define LP5523_PS (1)
+#define LP5523_NPS (0)
+
+/* mux LEDs */
+
+#define LP5523_MUX_LED1 (1)
+#define LP5523_MUX_LED2 (2)
+#define LP5523_MUX_LED3 (3)
+#define LP5523_MUX_LED4 (4)
+#define LP5523_MUX_LED5 (5)
+#define LP5523_MUX_LED6 (6)
+#define LP5523_MUX_LED7 (7)
+#define LP5523_MUX_LED8 (8)
+#define LP5523_MUX_LED9 (9)
+#define LP5523_MUX_GPO (16)
+
+/* map LEDs */
+
+#define LP5523_MAP_LED1 (0x0001)
+#define LP5523_MAP_LED2 (0x0002)
+#define LP5523_MAP_LED3 (0x0004)
+#define LP5523_MAP_LED4 (0x0008)
+#define LP5523_MAP_LED5 (0x0010)
+#define LP5523_MAP_LED6 (0x0020)
+#define LP5523_MAP_LED7 (0x0040)
+#define LP5523_MAP_LED8 (0x0080)
+#define LP5523_MAP_LED9 (0x0100)
+#define LP5523_MAP_GPO (0x8000)
+
+#define LP5523_INS_PARAM(ins, name, param) \
+    ((param << LP5523_INS_ ## ins ## _ ## name ## _POS) & \
+    LP5523_INS_ ## ins ## _ ## name ## _MASK)
+
+/*
+ * Generates a PWM ramp starting at the current value. At each step the output
+ * is incremented or decremented.
+ *
+ * prescale:
+ *      0 = 0.488ms cycle time.
+ *      1 = 15.625ms cycle time.
+ *
+ * step_time: Number of cycles per increment (1-31).
+ *
+ * sign:
+ *      0 = Increment.
+ *      1 = Decrement.
+ *
+ * noi: Number of increments (0-255).
+ */
+
+#define LP5523_INS_RAMP_IM_PRESCALE_POS (14)
+#define LP5523_INS_RAMP_IM_PRESCALE_MASK (0x4000)
+#define LP5523_INS_RAMP_IM_STEP_TIME_POS (9)
+#define LP5523_INS_RAMP_IM_STEP_TIME_MASK (0x3e00)
+#define LP5523_INS_RAMP_IM_SIGN_POS (8)
+#define LP5523_INS_RAMP_IM_SIGN_MASK (0x0100)
+#define LP5523_INS_RAMP_IM_NOI_POS (0)
+#define LP5523_INS_RAMP_IM_NOI_MASK (0x00ff)
+
+#define LP5523_INS_RAMP_IM(prescale, step_time, sign, noi) \
+    (0x0000 | \
+    LP5523_INS_PARAM(RAMP_IM, PRESCALE, prescale) | \
+    LP5523_INS_PARAM(RAMP_IM, STEP_TIME, step_time) | \
+    LP5523_INS_PARAM(RAMP_IM, SIGN, sign) | \
+    LP5523_INS_PARAM(RAMP_IM, NOI, noi))
+
+/*
+ * Generates a PWM ramp starting at the current value. At each step the output
+ * is incremented or decremented.
+ *
+ * prescale:
+ *      0 = 0.488ms cycle time.
+ *      1 = 15.625ms cycle time.
+ *
+ * sign:
+ *      0 = Increment.
+ *      1 = Decrement.
+ *
+ * step_time: Pointer to a variable containing the number of cycles per
+ * increment.
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *      The registers value should be in the range 1-31
+ *
+ * noi: Pointer to a variable containing the number of increments.
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+
+#define LP5523_INS_RAMP_PRESCALE_POS (5)
+#define LP5523_INS_RAMP_PRESCALE_MASK (0x0020)
+#define LP5523_INS_RAMP_SIGN_POS (4)
+#define LP5523_INS_RAMP_SIGN_MASK (0x0010)
+#define LP5523_INS_RAMP_STEP_TIME_POS (2)
+#define LP5523_INS_RAMP_STEP_TIME_MASK (0x000c)
+#define LP5523_INS_RAMP_NOI_POS (0)
+#define LP5523_INS_RAMP_NOI_MASK (0x0003)
+
+#define LP5523_INS_RAMP(prescale, sign, step_time, noi) \
+    (0x8400 | \
+    LP5523_INS_PARAM(RAMP, PRESCALE, prescale) | \
+    LP5523_INS_PARAM(RAMP, SIGN, sign) | \
+    LP5523_INS_PARAM(RAMP, STEP_TIME, step_time) | \
+    LP5523_INS_PARAM(RAMP, NOI, noi))
+
+/*
+ * Sets the PWM value for an output.
+ *
+ * pwm: The PWM value (0-255).
+ */
+
+#define LP5523_INS_SET_PWM_IM_PWM_POS (0)
+#define LP5523_INS_SET_PWM_IM_PWM_MASK (0x00ff)
+
+#define LP5523_INS_SET_PWM_IM(pwm) \
+    (0x4000 | \
+    LP5523_INS_PARAM(SET_PWM_IM, PWM, pwm))
+
+/*
+ * Sets the PWM value for an output.
+ *
+ * pwm: Pointer to a variable containing the PWM value.
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+
+#define LP5523_INS_SET_PWM_PWM_POS (0)
+#define LP5523_INS_SET_PWM_PWM_MASK (0x0003)
+
+#define LP5523_INS_SET_PWM(pwm) \
+    (0x8460 | \
+    LP5523_INS_PARAM(SET_PWM, PWM, pwm))
+
+/*
+ * Waits a given number of steps.
+ *
+ * prescale:
+ *      0 = 0.488ms cycle time.
+ *      1 = 15.625ms cycle time.
+ *
+ * step_time: Number of cycles per increment (1-31).
+ */
+
+#define LP5523_INS_WAIT(prescale, step_time) \
+    LP5523_INS_RAMP_IM(prescale, step_time, 0, 0)
+
+#define LP5523_INS_MUX_PAR_POS (0)
+#define LP5523_INS_MUX_PAR_MASK (0x007f)
+
+#define LP5523_INS_MUX(opcode, par) \
+    (opcode | \
+    LP5523_INS_PARAM(MUX, PAR, par))
+
+/*
+ * Defines the address of the start of the mapping table.
+ *
+ * addr: The address of the start of the mapping table (0-95).
+ */
+#define LP5523_INS_MUX_LD_START(addr) \
+    LP5523_INS_MUX(0x9e00, addr)
+
+/*
+ * Defines the address of the start of the mapping table and activates the 
first
+ * row.
+ *
+ * addr: The address of the start of the mapping table (0-95).
+ */
+#define LP5523_INS_MUX_MAP_START(addr) \
+    LP5523_INS_MUX(0x9c00, addr)
+
+/*
+ * Defines the address of the end of the mapping table.
+ *
+ * addr: The address of the end of the mapping table (0-95).
+ */
+#define LP5523_INS_MUX_LD_END(addr) \
+    LP5523_INS_MUX(0x9c80, addr)
+
+/*
+ * Connects one LED driver to the execution engine.
+ *
+ * sel: The LED to connect (0-16).
+ *      0 = no drivers
+ *      1-9 = LEDs.
+ *      16 = GPO.
+ */
+#define LP5523_INS_MUX_SEL(sel) \
+    LP5523_INS_MUX(0x9d00, sel)
+
+/*
+ * Clears engine to driver mapping.
+ */
+#define LP5523_INS_MUX_CLR() \
+    LP5523_INS_MUX_SEL(0)
+
+/*
+ * Increments the index pointer and sets that row active. Wraps to the start
+ * of the table if the end of the table is reached.
+ */
+#define LP5523_INS_MUX_MAP_NEXT() \
+    (0x9d80)
+
+/*
+ * Decrements the index pointer and sets that row active. Wraps to the end
+ * of the table if the start of the table is reached.
+ */
+#define LP5523_INS_MUX_MAP_PREV() \
+    (0x9dc0)
+
+/*
+ * Increments the index pointer. Wraps to the start of the table if the end
+ * of the table is reached.
+ */
+#define LP5523_INS_MUX_LD_NEXT() \
+    (0x9d81)
+
+/*
+ * Decrements the index pointer. Wraps to the end of the table if the start
+ * of the table is reached.
+ */
+#define LP5523_INS_MUX_LD_PREV() \
+    (0x9dc1)
+
+/*
+ * Sets the index pointer to point to a table row.
+ *
+ * addr: The absolute address of the table row (0-95).
+ */
+#define LP5523_INS_MUX_LD_ADDR(addr) \
+    LP5523_INS_MUX(0x9f00, addr)
+
+/*
+ * Sets the index pointer to point to a table row and sets that row active.
+ *
+ * addr: The absolute address of the table row (0-95).
+ */
+#define LP5523_INS_MUX_MAP_ADDR(addr) \
+    LP5523_INS_MUX(0x9f80, addr)
+
+/*
+ * Reset
+ */
+#define LP5523_INS_RST() \
+    (0x0000)
+
+/*
+ * Branches to an absolute address.
+ *
+ * step_number: The absolute address to branch to (0-95).
+ *
+ * loop_count: The number of times to branch, 0 indicates infintity.
+ */
+#define LP5523_INS_BRANCH_IM_LOOP_COUNT_POS (7)
+#define LP5523_INS_BRANCH_IM_LOOP_COUNT_MASK (0x01f80)
+#define LP5523_INS_BRANCH_IM_STEP_NUMBER_POS (0)
+#define LP5523_INS_BRANCH_IM_STEP_NUMBER_MASK (0x007f)
+
+#define LP5523_INS_BRANCH_IM(loop_count, step_number) \
+    (0xa000 | \
+    LP5523_INS_PARAM(BRANCH_IM, LOOP_COUNT, loop_count) | \
+    LP5523_INS_PARAM(BRANCH_IM, STEP_NUMBER, step_number))
+
+/*
+ * Branches to an absolute address.
+ *
+ * step_number: The absolute address to branch to (0-95).
+ *
+ * loop_count: Pointer to a variable containing the number of loops.
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+#define LP5523_INS_BRANCH_STEP_NUMBER_POS (2)
+#define LP5523_INS_BRANCH_STEP_NUMBER_MASK (0x01fc)
+#define LP5523_INS_BRANCH_LOOP_COUNT_POS (0)
+#define LP5523_INS_BRANCH_LOOP_COUNT_MASK (0x0003)
+
+#define LP5523_INS_BRANCH(step_number, loop_count) \
+    (0x8600 | \
+    LP5523_INS_PARAM(BRANCH, STEP_NUMBER, step_number) | \
+    LP5523_INS_PARAM(BRANCH, LOOP_COUNT, loop_count))
+
+#define LP5523_INS_INT() \
+    (0xc400)
+
+/*
+ * Ends the program execution.
+ */
+#define LP5523_INS_END_INTERRUPT_POS (12)
+#define LP5523_INS_END_INTERRUPT_MASK (0x1000)
+#define LP5523_INS_END_RESET_POS (11)
+#define LP5523_INS_END_RESET_MASK (0x0800)
+
+#define LP5523_INS_END(interrupt, reset) \
+    (0xc000 | \
+    LP5523_INS_PARAM(END, INTERRUPT, interrupt) | \
+    LP5523_INS_PARAM(END, RESET, reset))
+
+/*
+ * Wait on, or send triggers that can be waited on by or sent from other
+ * engines.
+ *
+ * wait_external: Wait for an external trigger.
+ *
+ * wait_engines: Wait for a trigger from one of these engines (3 bit value,
+ * each bit representing an engine the LSB being engine 1).
+ *
+ * send_external: Send an external trigger.
+ *
+ * send_engines: Send a trigger to all of these engines (3 bit value,
+ * each bit representing an engine the LSB being engine 1).
+ */
+#define LP5523_INS_TRIGGER_WAIT_EXTERNAL_POS (12)
+#define LP5523_INS_TRIGGER_WAIT_EXTERNAL_MASK (0x1000)
+#define LP5523_INS_TRIGGER_WAIT_ENGINES_POS (7)
+#define LP5523_INS_TRIGGER_WAIT_ENGINES_MASK (0x0310)
+#define LP5523_INS_TRIGGER_SEND_EXTERNAL_POS (6)
+#define LP5523_INS_TRIGGER_SEND_EXTERNAL_MASK (0x0040)
+#define LP5523_INS_TRIGGER_SEND_ENGINES_POS (1)
+#define LP5523_INS_TRIGGER_SEND_ENGINES_MASK (0x000e)
+
+#define LP5523_INS_TRIGGER(wait_external, wait_engines, send_external, \
+    send_engines) \
+    (0xe000 | \
+    LP5523_INS_PARAM(TRIGGER, WAIT_EXTERNAL, wait_external) | \
+    LP5523_INS_PARAM(TRIGGER, WAIT_ENGINES, wait_engines) | \
+    LP5523_INS_PARAM(TRIGGER, SEND_EXTERNAL, send_external) | \
+    LP5523_INS_PARAM(TRIGGER, SEND_ENGINES, send_engines))
+
+#define LP5523_INS_J_SKIP_POS (4)
+#define LP5523_INS_J_SKIP_MASK (0x01f0)
+#define LP5523_INS_J_VARIABLE1_POS (2)
+#define LP5523_INS_J_VARIABLE1_MASK (0x000c)
+#define LP5523_INS_J_VARIABLE2_POS (0)
+#define LP5523_INS_J_VARIABLE2_MASK (0x0003)
+
+#define LP5523_INS_J(opcode, skip, variable1, variable2) \
+    (opcode | \
+    LP5523_INS_PARAM(J, SKIP, skip) | \
+    LP5523_INS_PARAM(J, VARIABLE1, variable1) | \
+    LP5523_INS_PARAM(J, VARIABLE2, variable2))
+
+/*
+ * Skip if not equal.
+ *
+ * skip: Number of operations to be skipped if not equal (0-31).
+ *
+ * variable1: Compared to variable2 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *
+ * variable2: Compared to variable1 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+#define LP5523_INS_JNE(skip, variable1, variable2) \
+    LP5523_INS_J(0x8800, skip, variable1, variable2)
+
+/*
+ * Skip if less than.
+ *
+ * skip: Number of operations to be skipped if less (0-31).
+ *
+ * variable1: Compared to variable2 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *
+ * variable2: Compared to variable1 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+#define LP5523_INS_JL(skip, variable1, variable2) \
+    LP5523_INS_J(0x8a00, skip, variable1, variable2)
+
+/*
+ * Skip if greater or equal than.
+ *
+ * skip: Number of operations to be skipped if greater or equal (0-31).
+ *
+ * variable1: Compared to variable2 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *
+ * variable2: Compared to variable1 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+#define LP5523_INS_JGE(skip, variable1, variable2) \
+    LP5523_INS_J(0x8c00, skip, variable1, variable2)
+
+/*
+ * Skip if equal.
+ *
+ * skip: Number of operations to be skipped if equal (0-31).
+ *
+ * variable1: Compared to variable2 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *
+ * variable2: Compared to variable1 (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+
+#define LP5523_INS_JE(skip, variable1, variable2) \
+    LP5523_INS_J(0x8e00, skip, variable1, variable2)
+
+#define LP5523_INS_ARITH_TARGET_VARIABLE_POS (10)
+#define LP5523_INS_ARITH_TARGET_VARIABLE_MASK (0x0c00)
+
+#define LP5523_INS_ARITH_IM_VALUE_POS (0)
+#define LP5523_INS_ARITH_IM_VALUE_MASK (0x00ff)
+
+#define LP5523_INS_ARITH_IM(opcode, target_variable, value) \
+    (opcode | \
+    LP5523_INS_PARAM(ARITH, TARGET_VARIABLE, target_variable) | \
+    LP5523_INS_PARAM(ARITH_IM, VALUE, value))
+
+#define LP5523_INS_ARITH_VARIABLE1_POS (2)
+#define LP5523_INS_ARITH_VARIABLE1_MASK (0x000c)
+#define LP5523_INS_ARITH_VARIABLE2_POS (0)
+#define LP5523_INS_ARITH_VARIABLE2_MASK (0x0003)
+
+#define LP5523_INS_ARITH(opcode, target_variable, variable1, variable2) \
+    (opcode | \
+    LP5523_INS_PARAM(ARITH, TARGET_VARIABLE, target_variable) | \
+    LP5523_INS_PARAM(ARITH, VARIABLE1, variable1) | \
+    LP5523_INS_PARAM(ARITH, VARIABLE2, variable2))
+
+/*
+ * Load a value into a variable.
+ *
+ * target_variable: (0-2)
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *
+ * value:
+ */
+#define LP5523_INS_LD(target_variable, value) \
+    LP5523_INS_ARITH_IM(0x9000, target_variable, value)
+
+/*
+ * Add an immediate value to a variable, place the result back in the
+ * varible.
+ *
+ * target_variable: (0-2)
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *
+ * value:
+ */
+#define LP5523_INS_ADD_IM(target_variable, value) \
+    LP5523_INS_ARITH_IM(0x9100, target_variable, value)
+
+/*
+ * Add one variable to another, place the result in a third target variable.
+ *
+ * target_variable: (0-2)
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *
+ * variable1: Variable containing the augend (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *
+ * variable2: Variable containing the addend (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+#define LP5523_INS_ADD(target_variable, variable1, variable2) \
+    LP5523_INS_ARITH(0x9300, target_variable, variable1, variable2)
+
+/*
+ * Subtract an immediate value from a variable, place the result back in the
+ * varible.
+ *
+ * target_variable: (0-2)
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *
+ * value:
+ */
+#define LP5523_INS_SUB_IM(target_variable, value) \
+    LP5523_INS_ARITH_IM(0x9200, target_variable, value)
+
+/*
+ * Subtract one variable from another, place the result in a third target
+ * variable.
+ *
+ * target_variable: (0-2)
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *
+ * variable1: Variable containing the minuend (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ *
+ * variable2: Variable containing the subtrahend (0-3).
+ *      0 = local varible A.
+ *      1 = local variable B.
+ *      2 = global variable C.
+ *      3 = register address 0x3C variable D value or register address 0x42
+ *          value.
+ */
+#define LP5523_INS_SUB(target_variable, variable1, variable2) \
+    LP5523_INS_ARITH(0x9310, target_variable, variable1, variable2)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/drivers/lp5523/pkg.yml b/hw/drivers/lp5523/pkg.yml
new file mode 100644
index 000000000..a695429d2
--- /dev/null
+++ b/hw/drivers/lp5523/pkg.yml
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: hw/drivers/lp5523
+pkg.description: Driver for the TI LP5523
+pkg.author: "Apache Mynewt d...@mynewt.apache.org"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+    - led
+    - texas
+    - lp5523
+        
+pkg.deps:
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/hw/sensor"
+
+pkg.deps.LP5523_CLI:
+    - "@apache-mynewt-core/util/parse"
+
+pkg.req_apis:
+    - stats
+    - log
\ No newline at end of file
diff --git a/hw/drivers/lp5523/src/lp5523.c b/hw/drivers/lp5523/src/lp5523.c
new file mode 100644
index 000000000..e466919b3
--- /dev/null
+++ b/hw/drivers/lp5523/src/lp5523.c
@@ -0,0 +1,878 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <defs/error.h>
+#include <sysinit/sysinit.h>
+#include <hal/hal_i2c.h>
+#include <log/log.h>
+#include <stats/stats.h>
+
+#include "lp5523/lp5523.h"
+
+/* Define the stats section and records */
+STATS_SECT_START(lp5523_stat_section)
+    STATS_SECT_ENTRY(read_errors)
+    STATS_SECT_ENTRY(write_errors)
+STATS_SECT_END
+
+/* Define stat names for querying */
+STATS_NAME_START(lp5523_stat_section)
+    STATS_NAME(lp5523_stat_section, read_errors)
+    STATS_NAME(lp5523_stat_section, write_errors)
+STATS_NAME_END(lp5523_stat_section)
+
+/* Global variable used to hold stats data */
+STATS_SECT_DECL(lp5523_stat_section) g_lp5523stats;
+
+#define LOG_MODULE_LP5523    (5523)
+#define LP5523_INFO(...)     LOG_INFO(&_log, LOG_MODULE_LP5523, __VA_ARGS__)
+#define LP5523_ERR(...)      LOG_ERROR(&_log, LOG_MODULE_LP5523, __VA_ARGS__)
+static struct log _log;
+
+int
+lp5523_set_reg(struct sensor_itf *itf, enum lp5523_registers addr,
+    uint8_t value)
+{
+    int rc;
+    uint8_t payload[2] = { addr, value };
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 2,
+        .buffer = payload
+    };
+
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              OS_TICKS_PER_SEC / 10, 1);
+
+    if (rc != 0) {
+        LP5523_ERR("Failed to write to 0x%02X:0x%02X with value 0x%02X\n",
+                       itf->si_addr, addr, value);
+        STATS_INC(g_lp5523stats, read_errors);
+    }
+
+    return rc;
+}
+
+int
+lp5523_get_reg(struct sensor_itf *itf, enum lp5523_registers addr,
+    uint8_t *value)
+{
+    int rc;
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 1,
+        .buffer = &addr
+    };
+
+    /* Register write */
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              OS_TICKS_PER_SEC / 10, 0);
+    if (rc != 0) {
+        LP5523_ERR("I2C access failed at address 0x%02X\n", itf->si_addr);
+        STATS_INC(g_lp5523stats, write_errors);
+        return rc;
+    }
+
+    /* Read one byte back */
+    data_struct.buffer = value;
+    rc = hal_i2c_master_read(itf->si_num, &data_struct,
+                             OS_TICKS_PER_SEC / 10, 1);
+
+    if (rc != 0) {
+         LP5523_ERR("Failed to read from 0x%02X:0x%02X\n", itf->si_addr, addr);
+         STATS_INC(g_lp5523stats, read_errors);
+    }
+    return rc;
+}
+
+static int
+lp5523_set_2_regs(struct sensor_itf *itf, enum lp5523_registers addr,
+    uint8_t vals[2])
+{
+    int rc;
+    uint8_t regs[3];
+
+    regs[0] = addr ;
+    regs[1] = vals[0];
+    regs[2] = vals[1];
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 3,
+        .buffer = regs
+    };
+
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              (OS_TICKS_PER_SEC / 5), 1);
+
+    if (rc != 0) {
+        LP5523_ERR("Failed to write to 0x%02X:0x%02X\n", itf->si_addr, 
regs[0]);
+        STATS_INC(g_lp5523stats, read_errors);
+    }
+    return rc;
+}
+
+/* XXX: Not sure if ai-read is supported, seems to work for reads of length 2 
*/
+static int
+lp5523_get_2_regs(struct sensor_itf *itf, enum lp5523_registers addr,
+    uint8_t vals[2])
+{
+    int rc;
+    uint8_t addr_b = (uint8_t) addr;
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 1,
+        .buffer = &addr_b
+    };
+
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+        (OS_TICKS_PER_SEC / 10), 0);
+
+    if (rc != 0) {
+        LP5523_ERR("Failed to write to 0x%02X:0x%02X\n", itf->si_addr, addr_b);
+        STATS_INC(g_lp5523stats, read_errors);
+        return rc;
+    }
+
+    data_struct.len = 2;
+    data_struct.buffer = vals;
+    rc = hal_i2c_master_read(itf->si_num, &data_struct,
+        OS_TICKS_PER_SEC / 5, 1);
+
+    if (rc != 0) {
+         LP5523_ERR("Failed to read from 0x%02X:0x%02X\n", itf->si_addr,
+            addr_b);
+         STATS_INC(g_lp5523stats, read_errors);
+    }
+    return rc;
+}
+
+static void
+lp5523_wait(uint32_t ms)
+{
+    os_time_delay(((ms * OS_TICKS_PER_SEC) / 1000) + 1);
+}
+
+int lp5523_apply_value(struct lp5523_register_value addr, uint8_t value,
+    uint8_t *reg)
+{
+    value <<= addr.pos;
+
+    if ((value & (~addr.mask)) != 0) {
+        return -1;
+    }
+
+    *reg &= ~addr.mask;
+    *reg |= value;
+
+    return 0;
+}
+
+int
+lp5523_set_value(struct sensor_itf *itf, struct lp5523_register_value addr,
+    uint8_t value)
+{
+    int rc;
+    uint8_t reg;
+
+    rc = lp5523_get_reg(itf, addr.reg, &reg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = lp5523_apply_value(addr, value, &reg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return lp5523_set_reg(itf, addr.reg, reg);
+}
+
+int
+lp5523_get_value(struct sensor_itf *itf, struct lp5523_register_value addr,
+    uint8_t *value)
+{
+    int rc;
+    uint8_t reg;
+
+    rc = lp5523_get_reg(itf, addr.reg, &reg);
+
+    *value = (reg & addr.mask) >> addr.pos;
+
+    return rc;
+}
+
+int
+lp5523_set_bitfield(struct sensor_itf *itf, enum lp5523_bitfield_registers 
addr,
+    uint16_t outputs)
+{
+    uint8_t vals[2] = { (outputs >> 8) & 0x01, outputs & 0xff };
+
+    return lp5523_set_2_regs(itf, addr, vals);
+}
+
+int
+lp5523_get_bitfield(struct sensor_itf *itf, enum lp5523_bitfield_registers 
addr,
+    uint16_t* outputs)
+{
+    int rc;
+    uint8_t vals[2];
+
+    rc = lp5523_get_2_regs(itf, addr, vals);
+
+    *outputs = ((vals[0] & 0x01) << 8) | vals[1];
+
+    return rc;
+}
+
+int
+lp5523_set_output_reg(struct sensor_itf *itf, enum lp5523_output_registers 
addr,
+    uint8_t output, uint8_t value)
+{
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+    return lp5523_set_reg(itf, addr + (output - 1), value);
+}
+
+int
+lp5523_get_output_reg(struct sensor_itf *itf, enum lp5523_output_registers 
addr,
+    uint8_t output, uint8_t *value)
+{
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+    return lp5523_get_reg(itf, addr + (output - 1), value);
+}
+
+int
+lp5523_set_engine_reg(struct sensor_itf *itf, enum lp5523_engine_registers 
addr,
+    uint8_t engine, uint8_t value)
+{
+    if ((engine < 1) || (engine > 3)) {
+        return -1;
+    }
+    return lp5523_set_reg(itf, addr + (engine - 1), value);
+}
+
+int
+lp5523_get_engine_reg(struct sensor_itf *itf, enum lp5523_engine_registers 
addr,
+    uint8_t engine, uint8_t *value)
+{
+    if ((engine < 1) || (engine > 3)) {
+        return -1;
+    }
+    return lp5523_get_reg(itf, addr + (engine - 1), value);
+}
+
+int
+lp5523_set_enable(struct sensor_itf *itf, uint8_t enable)
+{
+    int rc;
+
+    rc = lp5523_set_value(itf, LP5523_CHIP_EN, enable);
+
+    if ((rc == 0) && (enable)) {
+        lp5523_wait(1);
+    }
+    return rc;
+}
+
+int
+lp5523_set_engine_control(struct sensor_itf *itf,
+    enum lp5523_engine_control_registers addr, uint8_t engine_mask, uint8_t 
values)
+{
+    uint8_t reg;
+    int rc;
+
+    if (((engine_mask & LP5523_ENGINE1_MASK) != LP5523_ENGINE1_MASK) &&
+        ((engine_mask & LP5523_ENGINE2_MASK) != LP5523_ENGINE2_MASK) &&
+        ((engine_mask & LP5523_ENGINE3_MASK) != LP5523_ENGINE3_MASK)) {
+        return -1;
+    }
+
+    rc = lp5523_get_reg(itf, addr, &reg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    reg &= ~engine_mask;
+    reg |= engine_mask & values;
+
+    return lp5523_set_reg(itf, addr, reg);
+}
+
+int
+lp5523_set_output_mapping(struct sensor_itf *itf, uint8_t output,
+    uint8_t mapping)
+{
+    struct lp5523_register_value reg;
+
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+
+    reg = LP5523_OUTPUT_MAPPING;
+    reg.reg += output - 1;
+
+    return lp5523_set_value(itf, reg, mapping);
+}
+
+int
+lp5523_get_output_mapping(struct sensor_itf *itf, uint8_t output,
+    uint8_t *mapping)
+{
+    struct lp5523_register_value reg;
+
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+
+    reg = LP5523_OUTPUT_MAPPING;
+    reg.reg += output - 1;
+
+    return lp5523_get_value(itf, reg, mapping);
+}
+
+int
+lp5523_set_output_log_dim(struct sensor_itf *itf, uint8_t output,
+    uint8_t enable)
+{
+    struct lp5523_register_value reg;
+
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+
+    reg = LP5523_OUTPUT_LOG_EN;
+    reg.reg += output - 1;
+
+    return lp5523_set_value(itf, reg, enable);
+}
+
+int
+lp5523_get_output_log_dim(struct sensor_itf *itf, uint8_t output,
+    uint8_t *enable)
+{
+    struct lp5523_register_value reg;
+
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+
+    reg = LP5523_OUTPUT_LOG_EN;
+    reg.reg += output - 1;
+
+    return lp5523_get_value(itf, reg, enable);
+}
+
+int
+lp5523_set_output_temp_comp(struct sensor_itf *itf, uint8_t output,
+    uint8_t value)
+{
+    struct lp5523_register_value reg;
+
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+
+    reg = LP5523_OUTPUT_TEMP_COMP;
+    reg.reg += output - 1;
+
+    return lp5523_set_value(itf, reg, value);
+}
+
+int
+lp5523_get_output_temp_comp(struct sensor_itf *itf, uint8_t output,
+    uint8_t *value)
+{
+    struct lp5523_register_value reg;
+
+    if ((output < 1) || (output > 9)) {
+        return -1;
+    }
+
+    reg = LP5523_OUTPUT_TEMP_COMP;
+    reg.reg += output - 1;
+
+    return lp5523_get_value(itf, reg, value);
+}
+
+int
+lp5523_get_engine_int(struct sensor_itf *itf, uint8_t engine, uint8_t *flag)
+{
+    struct lp5523_register_value reg;
+
+    if ((engine < 1) || (engine > 3)) {
+        return -1;
+    }
+
+    reg = LP5523_ENG1_INT;
+    reg.pos >>= engine - 1;
+
+    return lp5523_get_value(itf, reg, flag);
+}
+
+int
+lp5523_reset(struct sensor_itf *itf)
+{
+    return lp5523_set_reg(itf, LP5523_RESET, 0xff);
+}
+
+int
+lp5523_set_page_sel(struct sensor_itf *itf, uint8_t page)
+{
+    if (page > 5) {
+        return -1;
+    }
+    return lp5523_set_reg(itf, LP5523_PROG_MEM_PAGE_SEL, page);
+}
+
+int
+lp5523_set_engine_mapping(struct sensor_itf *itf, uint8_t engine,
+    uint16_t outputs)
+{
+    if ((engine < 1) || (engine > 3)) {
+        return -1;
+    }
+
+    return lp5523_set_bitfield(itf, LP5523_ENG_MAPPING + ((engine - 1) << 1),
+        outputs);
+}
+
+int
+lp5523_get_engine_mapping(struct sensor_itf *itf, uint8_t engine,
+    uint16_t *outputs)
+{
+    if ((engine < 1) || (engine > 3)) {
+        return -1;
+    }
+
+    return lp5523_get_bitfield(itf, LP5523_ENG_MAPPING + ((engine - 1) << 1),
+        outputs);
+}
+
+static int
+lp5523_set_pr_instruction(struct sensor_itf *itf, uint8_t addr, uint16_t *ins)
+{
+    uint8_t mem[2] = { ((*ins) >> 8) & 0x00ff, (*ins) & 0x00ff };
+
+    return lp5523_set_2_regs(itf, LP5523_PROGRAM_MEMORY + (addr << 1), mem);
+}
+
+static int
+lp5523_get_pr_instruction(struct sensor_itf *itf, uint8_t addr, uint16_t *ins)
+{
+    int rc;
+    uint8_t mem[2];
+
+    rc = lp5523_get_2_regs(itf, LP5523_PROGRAM_MEMORY + (addr << 1), mem);
+
+    *ins = (((uint16_t)mem[0]) << 8) | mem[1];
+
+    return rc;
+}
+
+static int
+lp5523_verify_pr_instruction(struct sensor_itf *itf, uint8_t addr,
+    uint16_t *ins)
+{
+    int rc;
+    uint8_t mem[2];
+    uint16_t ver;
+
+    rc = lp5523_get_2_regs(itf, LP5523_PROGRAM_MEMORY + (addr << 1), mem);
+    if (rc != 0) {
+        return rc;
+    }
+
+    ver = ((((uint16_t)mem[0]) << 8) | mem[1]);
+
+    return (*ins != ver) ? 1 : 0;
+}
+
+
+static int
+lp5523_rwv_page(struct sensor_itf *itf, int(*irwv)(struct sensor_itf *,
+    uint8_t, uint16_t *), uint8_t page, uint16_t* pgm,
+    uint8_t start, uint8_t size)
+{
+    int rc;
+    uint8_t i;
+
+    rc = lp5523_set_page_sel(itf, page);
+    if (rc != 0) {
+        return rc;
+    }
+
+    i = 0;
+    while (i < size) {
+        rc = irwv(itf, start, pgm + i);
+        if (rc != 0) {
+            return rc;
+        }
+        ++start;
+        ++i;
+    }
+    return 0;
+}
+
+static int
+lp5523_set_page(struct sensor_itf *itf, uint8_t page, uint16_t* pgm,
+    uint8_t start, uint8_t size)
+{
+    return lp5523_rwv_page(itf, &lp5523_set_pr_instruction, page, pgm, start,
+        size);
+}
+
+static int
+lp5523_get_page(struct sensor_itf *itf, uint8_t page, uint16_t* pgm,
+    uint8_t start, uint8_t size)
+{
+    return lp5523_rwv_page(itf, &lp5523_get_pr_instruction, page, pgm, start,
+        size);
+}
+
+static int
+lp5523_verify_page(struct sensor_itf *itf, uint8_t page, uint16_t* pgm,
+    uint8_t start, uint8_t size)
+{
+    return lp5523_rwv_page(itf, &lp5523_verify_pr_instruction, page, pgm, 
start,
+        size);
+}
+
+static int
+lp5523_rwv_program(struct sensor_itf *itf, int(*prw)(struct sensor_itf *,
+    uint8_t, uint16_t *, uint8_t, uint8_t), uint16_t* pgm, uint8_t start,
+    uint8_t size)
+{
+    int rc;
+    uint8_t page;
+    uint8_t last_page;
+    uint8_t start_rel;
+    uint8_t end;
+
+    if (((start + size) > LP5523_MEMORY_SIZE) || (size == 0)) {
+        return -1;
+    }
+
+    end = start + size;
+    page = start / LP5523_PAGE_SIZE;
+    last_page = (end - 1) / LP5523_PAGE_SIZE;
+    start_rel = start % LP5523_PAGE_SIZE;
+
+    if (page == last_page) {
+        rc = prw(itf, page, pgm, start_rel, size);
+        if (rc != 0) {
+            return rc;
+        }
+    } else {
+        uint8_t end_rel;
+        uint8_t write_size;
+
+        write_size = LP5523_PAGE_SIZE - start_rel;
+        rc = prw(itf, page, pgm, start_rel, write_size);
+        if (rc != 0) {
+            return rc;
+        }
+        ++page;
+        pgm += write_size;
+
+        while (page < last_page) {
+            rc = prw(itf, page, pgm, 0, LP5523_PAGE_SIZE);
+            if (rc != 0) {
+                return rc;
+            }
+            ++page;
+            pgm += LP5523_PAGE_SIZE;
+        }
+
+        end_rel = end % LP5523_PAGE_SIZE;
+        write_size = (end_rel != 0) ? end_rel : LP5523_PAGE_SIZE;
+        return prw(itf, page, pgm, 0, write_size);
+    }
+    return 0;
+}
+
+int
+lp5523_set_instruction(struct sensor_itf *itf, uint8_t addr, uint16_t ins)
+{
+    int rc;
+
+    rc = lp5523_set_page_sel(itf, addr / LP5523_PAGE_SIZE);
+    return (rc != 0) ? rc : lp5523_set_pr_instruction(itf,
+        addr % LP5523_PAGE_SIZE, &ins);
+}
+
+int
+lp5523_get_instruction(struct sensor_itf *itf, uint8_t addr, uint16_t *ins)
+{
+    int rc;
+
+    rc = lp5523_set_page_sel(itf, addr / LP5523_PAGE_SIZE);
+    return (rc != 0) ? rc : lp5523_get_pr_instruction(itf,
+        addr % LP5523_PAGE_SIZE, ins);
+}
+
+int
+lp5523_set_program(struct sensor_itf *itf, uint8_t engine_mask, uint16_t *pgm,
+    uint8_t start, uint8_t size)
+{
+    int rc;
+
+    if (((start + size) > LP5523_MEMORY_SIZE) || (size == 0)) {
+        return -1;
+    }
+
+    /* disable engines */
+    rc = lp5523_set_engine_control(itf, LP5523_ENGINE_CNTRL2, engine_mask,
+        LP5523_ENGINES_DISABLED);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* put engines into load program state */
+    rc = lp5523_set_engine_control(itf, LP5523_ENGINE_CNTRL2, engine_mask,
+        LP5523_ENGINES_LOAD_PROGRAM);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* wait for engine busy */
+    lp5523_wait(1);
+
+    return lp5523_rwv_program(itf, &lp5523_set_page, pgm, start, size);
+}
+
+int
+lp5523_get_program(struct sensor_itf *itf, uint16_t *pgm, uint8_t start,
+    uint8_t size)
+{
+    return lp5523_rwv_program(itf, &lp5523_get_page, pgm, start, size);
+}
+
+int
+lp5523_verify_program(struct sensor_itf *itf, uint16_t *pgm, uint8_t start,
+    uint8_t size)
+{
+    return lp5523_rwv_program(itf, &lp5523_verify_page, pgm, start, size);
+}
+
+int
+lp5523_engines_run(struct sensor_itf *itf, uint8_t engine_mask)
+{
+    int rc;
+
+    rc = lp5523_set_engine_control(itf, LP5523_ENGINE_CNTRL1, engine_mask,
+        LP5523_ENGINES_FREE_RUN);
+    return (rc != 0) ? rc : lp5523_set_engine_control(itf, 
LP5523_ENGINE_CNTRL2,
+        engine_mask, LP5523_ENGINES_RUN_PROGRAM);
+}
+
+int
+lp5523_engines_hold(struct sensor_itf *itf, uint8_t engine_mask)
+{
+    return lp5523_set_engine_control(itf, LP5523_ENGINE_CNTRL1, engine_mask,
+        LP5523_ENGINES_HOLD);
+}
+
+int
+lp5523_engines_step(struct sensor_itf *itf, uint8_t engine_mask)
+{
+    return lp5523_set_engine_control(itf, LP5523_ENGINE_CNTRL1, engine_mask,
+        LP5523_ENGINES_STEP);
+}
+
+int
+lp5523_engines_disable(struct sensor_itf *itf, uint8_t engine_mask)
+{
+    return lp5523_set_engine_control(itf, LP5523_ENGINE_CNTRL2, engine_mask,
+        LP5523_ENGINES_DISABLED);
+}
+
+int
+lp5523_read_adc(struct sensor_itf *itf, uint8_t pin, uint8_t *v) {
+    int rc;
+
+    if (pin > 0x1f) {
+        return -1;
+    }
+
+    rc = lp5523_set_reg(itf, LP5523_LED_TEST_CONTROL,
+        pin | LP5523_EN_LED_TEST_ADC.mask);
+    if (rc != 0) {
+        return rc;
+    }
+
+    lp5523_wait(3);
+
+    return lp5523_get_reg(itf, LP5523_LED_TEST_ADC, v);
+}
+
+int
+lp5523_self_test(struct sensor_itf *itf) {
+    int rc;
+    uint8_t status;
+    uint8_t misc;
+    uint8_t vdd;
+    uint8_t adc;
+    uint8_t i;
+
+    rc = lp5523_get_reg(itf, LP5523_STATUS, &status);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = lp5523_get_reg(itf, LP5523_MISC, &misc);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* if external clock is forced, check it is detected */
+    if ((((misc & (LP5523_CLK_DET_EN.mask | LP5523_INT_CLK_EN.mask))) == 0) &&
+        ((status & LP5523_EXT_CLK_USED.mask) == 0)) {
+        return -2;
+    }
+
+    /* measure VDD */
+    rc = lp5523_read_adc(itf, LP5523_LED_TEST_VDD, &vdd);
+    if (rc != 0) {
+        return rc;
+    }
+
+    i = 1;
+    while (i <= 9) {
+        /* set LED PWM to 0xff */
+        rc = lp5523_set_output_reg(itf, LP5523_PWM, i, 0xff);
+        if (rc != 0) {
+            return rc;
+        }
+
+        /* wait to stabilise */
+        lp5523_wait(4);
+
+        /* read the ADC */
+        rc = lp5523_read_adc(itf, i - 1, &adc);
+        if (rc != 0) {
+            return rc;
+        }
+        if ((adc > vdd) || (adc < LP5523_LED_TEST_SC_LIM)) {
+            return -3;
+        }
+
+        rc = lp5523_set_output_reg(itf, LP5523_PWM, i, 0x00);
+        if (rc != 0) {
+            return rc;
+        }
+        ++i;
+    }
+
+    return 0;
+}
+
+int
+lp5523_init(struct os_dev *dev, void *arg)
+{
+    struct lp5523 *lp;
+    struct sensor *sensor;
+    int rc;
+
+    if (!arg || !dev) {
+        return SYS_ENODEV;
+    }
+
+    lp = (struct lp5523 *)dev;
+
+    log_register(dev->od_name, &_log, &log_console_handler, NULL,
+        LOG_SYSLEVEL);
+
+    sensor = &lp->sensor;
+
+    /* Initialise the stats entry */
+    rc = stats_init(
+        STATS_HDR(g_lp5523stats),
+        STATS_SIZE_INIT_PARMS(g_lp5523stats, STATS_SIZE_32),
+        STATS_NAME_INIT_PARMS(lp5523_stat_section));
+    SYSINIT_PANIC_ASSERT(rc == 0);
+    /* Register the entry with the stats registry */
+    rc = stats_register(dev->od_name, STATS_HDR(g_lp5523stats));
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    rc = sensor_init(sensor, dev);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = sensor_set_interface(sensor, arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return sensor_mgr_register(sensor);
+}
+
+int
+lp5523_config(struct lp5523 *lp, struct lp5523_cfg *cfg)
+{
+    int rc;
+    struct sensor_itf *itf;
+    uint8_t misc_val;
+
+    itf = SENSOR_GET_ITF(&(lp->sensor));
+
+    itf->si_addr = LP5523_I2C_BASE_ADDR + cfg->asel;
+
+    rc = lp5523_reset(itf);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* chip enable */
+    rc = lp5523_set_enable(itf, 1);
+    if (rc != 0) {
+        return rc;
+    }
+
+    misc_val = LP5523_EN_AUTO_INCR.mask;
+
+    rc = lp5523_apply_value(LP5523_CLK_DET_EN, cfg->clk_det_en, &misc_val);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = lp5523_apply_value(LP5523_INT_CLK_EN, cfg->int_clk_en, &misc_val);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = lp5523_apply_value(LP5523_CP_MODE, cfg->cp_mode, &misc_val);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = lp5523_set_reg(itf, LP5523_MISC, misc_val);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return lp5523_set_value(itf, LP5523_INT_CONF, cfg->int_conf);
+}
diff --git a/hw/drivers/lp5523/src/lp5523_shell.c 
b/hw/drivers/lp5523/src/lp5523_shell.c
new file mode 100644
index 000000000..669a42e4b
--- /dev/null
+++ b/hw/drivers/lp5523/src/lp5523_shell.c
@@ -0,0 +1,1018 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include "sysinit/sysinit.h"
+#include "console/console.h"
+#include "sensor/sensor.h"
+#include "shell/shell.h"
+#include "hal/hal_gpio.h"
+#include "lp5523/lp5523.h"
+#include "parse/parse.h"
+
+#if MYNEWT_VAL(LP5523_CLI)
+
+static int lp5523_shell_cmd(int argc, char **argv);
+
+static struct shell_cmd lp5523_shell_cmd_struct = {
+    .sc_cmd = "lp5523",
+    .sc_cmd_func = lp5523_shell_cmd
+};
+
+static struct sensor_itf lp5523_itf = {
+    .si_type = MYNEWT_VAL(LP5523_SHELL_ITF_TYPE),
+    .si_num = MYNEWT_VAL(LP5523_SHELL_ITF_NUM),
+    .si_addr = MYNEWT_VAL(LP5523_SHELL_ITF_ADDR)
+};
+
+static int
+lp5523_shell_err_too_few_args(char *cmd_name)
+{
+    console_printf("Error: too few arguments for command \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+lp5523_shell_err_too_many_args(char *cmd_name)
+{
+    console_printf("Error: too many arguments for command \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+lp5523_shell_err_unknown_arg(char *cmd_name)
+{
+    console_printf("Error: unknown argument \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+lp5523_shell_err_invalid_arg(char *cmd_name)
+{
+    console_printf("Error: invalid argument \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+lp5523_shell_help(void)
+{
+    console_printf("%s cmd [flags...]\n", lp5523_shell_cmd_struct.sc_cmd);
+    console_printf("cmd:\n");
+    console_printf("\treset\n");
+    console_printf("\tenable\t[output]\n");
+    console_printf("\tdisable\t[output]\n");
+    console_printf("\tpwm\t[output | value]\n");
+    console_printf("\tins\t[XXX]\n");
+    return 0;
+}
+
+static int
+lp5523_shell_cmd_reset(int argc, char **argv)
+{
+    return lp5523_reset(&lp5523_itf);
+}
+
+static int
+lp5523_shell_cmd_enable(int argc, char **argv)
+{
+    return lp5523_set_enable(&lp5523_itf, 1);
+}
+
+static int
+lp5523_shell_cmd_disable(int argc, char **argv)
+{
+    return lp5523_set_enable(&lp5523_itf, 0);
+}
+
+static int
+lp5523_shell_cmd_pwm(int argc, char **argv)
+{
+    int rc;
+    uint8_t output;
+    uint8_t value;
+
+    if (argc > 4) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 4) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    output = parse_ll_bounds(argv[2], 1, 9, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+    value = parse_ll_bounds(argv[3], 0, 255, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[3]);
+    }
+
+    return lp5523_set_output_reg(&lp5523_itf, LP5523_PWM, output, value);
+}
+
+static int
+lp5523_shell_cmd_ins_ramp(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    int snoi;
+    uint8_t prescale;
+    uint8_t step_time;
+    uint8_t sign;
+    uint8_t noi;
+
+    if (argc > 8) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 8) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    if (strcmp(argv[4], "im") == 0) {
+        prescale = parse_ll_bounds(argv[5], 0, 1, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[5]);
+        }
+
+        step_time = parse_ll_bounds(argv[6], 0, 31, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[6]);
+        }
+
+        snoi = parse_ll_bounds(argv[7], -255, 255, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[7]);
+        }
+
+        if (snoi < 0) {
+            sign = 1;
+            noi = (uint8_t)-snoi;
+        } else {
+            sign = 0;
+            noi = (uint8_t)snoi;
+        }
+
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_RAMP_IM(prescale, step_time, sign, noi));
+    }
+
+    prescale = parse_ll_bounds(argv[4], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    step_time = parse_ll_bounds(argv[5], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    sign = parse_ll_bounds(argv[6], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[6]);
+    }
+
+    noi = parse_ll_bounds(argv[7], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[7]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr,
+        LP5523_INS_RAMP(prescale, step_time, sign, noi));
+}
+
+static int
+lp5523_shell_cmd_ins_pwm(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t pwm;
+
+    if (argc > 6) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 5) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+
+    if (strcmp(argv[4], "im") == 0) {
+        if (argc < 6) {
+            return lp5523_shell_err_too_few_args(argv[1]);
+        }
+
+        pwm = parse_ll_bounds(argv[5], 0, 255, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[5]);
+        }
+
+        return lp5523_set_instruction(&lp5523_itf, addr, 
LP5523_INS_SET_PWM_IM(pwm));
+    }
+    if (argc > 5) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    pwm = parse_ll_bounds(argv[4], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr, LP5523_INS_SET_PWM(pwm));
+}
+
+static int
+lp5523_shell_cmd_ins_wait(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t prescale;
+    uint8_t step_time;
+
+    if (argc > 6) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 6) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    prescale = parse_ll_bounds(argv[4], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    step_time = parse_ll_bounds(argv[5], 0, 31, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr, LP5523_INS_WAIT(prescale,
+        step_time));
+}
+
+static int
+lp5523_shell_cmd_ins_mux_addr(int argc, char **argv, uint8_t *addr)
+{
+    int rc;
+    
+    if (argc < 7) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    *addr = parse_ll_bounds(argv[6], 0, 95, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[6]);
+    }
+    
+    return 0;
+}
+
+static int
+lp5523_shell_cmd_ins_mux(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+
+    if (argc > 7) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 5) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    if (strcmp(argv[4], "ld") == 0) {
+        if (argc < 6) {
+            return lp5523_shell_err_too_few_args(argv[1]);
+        }
+        if (strcmp(argv[5], "start") == 0) {
+            uint8_t addr;
+            
+            rc = lp5523_shell_cmd_ins_mux_addr(argc, argv, &addr);
+            if (rc != 0) {
+                return rc;
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_LD_START(addr));
+        }
+        if (strcmp(argv[5], "end") == 0) {
+            uint8_t addr;
+
+            rc = lp5523_shell_cmd_ins_mux_addr(argc, argv, &addr);
+            if (rc != 0) {
+                return rc;
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_LD_END(addr));
+        }
+        if (strcmp(argv[5], "addr") == 0) {
+            uint8_t addr;
+
+            rc = lp5523_shell_cmd_ins_mux_addr(argc, argv, &addr);
+            if (rc != 0) {
+                return rc;
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_LD_ADDR(addr));
+        }
+        if (strcmp(argv[5], "next") == 0) {
+            if (argc > 6) {
+                return lp5523_shell_err_too_many_args(argv[1]);
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_LD_NEXT());
+        }
+        if (strcmp(argv[5], "prev") == 0) {
+            if (argc > 6) {
+                return lp5523_shell_err_too_many_args(argv[1]);
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_LD_PREV());
+        }
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+    if (strcmp(argv[4], "map") == 0) {
+        if (argc < 6) {
+            return lp5523_shell_err_too_few_args(argv[1]);
+        }
+        if (strcmp(argv[5], "start") == 0) {
+            uint8_t addr;
+
+            rc = lp5523_shell_cmd_ins_mux_addr(argc, argv, &addr);
+            if (rc != 0) {
+                return rc;
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_MAP_START(addr));
+        }
+        if (strcmp(argv[5], "addr") == 0) {
+            uint8_t addr;
+
+            rc = lp5523_shell_cmd_ins_mux_addr(argc, argv, &addr);
+            if (rc != 0) {
+                return rc;
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_MAP_ADDR(addr));
+        }
+        if (strcmp(argv[5], "next") == 0) {
+            if (argc > 6) {
+                return lp5523_shell_err_too_many_args(argv[1]);
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_MAP_NEXT());
+        }
+        if (strcmp(argv[5], "prev") == 0) {
+            if (argc > 6) {
+                return lp5523_shell_err_too_many_args(argv[1]);
+            }
+
+            return lp5523_set_instruction(&lp5523_itf, addr,
+                LP5523_INS_MUX_MAP_PREV());
+        }
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+    if (strcmp(argv[4], "sel") == 0) {
+        uint8_t sel;
+
+        if (argc > 6) {
+            return lp5523_shell_err_too_many_args(argv[1]);
+        } else if (argc < 6) {
+            return lp5523_shell_err_too_few_args(argv[1]);
+        }
+
+        sel = parse_ll_bounds(argv[5], 0, 127, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[5]);
+        }
+
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_MUX_SEL(sel));
+    }
+    if (strcmp(argv[4], "clr") == 0) {
+        if (argc > 5) {
+            return lp5523_shell_err_too_many_args(argv[1]);
+        }
+        return lp5523_set_instruction(&lp5523_itf, addr, LP5523_INS_MUX_CLR());
+    }
+
+    return lp5523_shell_err_invalid_arg(argv[4]);
+}
+
+static int
+lp5523_shell_cmd_ins_rst(int argc, char **argv, uint8_t addr)
+{
+    if (argc > 4) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 4) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr, LP5523_INS_RST());
+}
+
+static int
+lp5523_shell_cmd_ins_branch(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t loop_count;
+    uint8_t step_number;
+
+    if (argc > 7) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 6) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    if (strcmp(argv[4], "im") == 0) {
+        if (argc < 7) {
+            return lp5523_shell_err_too_few_args(argv[1]);
+        }
+
+        loop_count = parse_ll_bounds(argv[5], 0, 63, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[5]);
+        }
+
+        step_number = parse_ll_bounds(argv[6], 0, 95, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[6]);
+        }
+
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_BRANCH_IM(loop_count, step_number));
+    }
+    if (argc > 6) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    step_number = parse_ll_bounds(argv[4], 0, 95, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    loop_count = parse_ll_bounds(argv[5], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr,
+        LP5523_INS_BRANCH(step_number, loop_count));
+}
+
+static int
+lp5523_shell_cmd_ins_int(int argc, char **argv, uint8_t addr)
+{
+    if (argc > 3) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 3) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr, LP5523_INS_INT());
+}
+
+static int
+lp5523_shell_cmd_ins_end(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t interrupt;
+    uint8_t reset;
+
+    if (argc > 6) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 6) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    interrupt = parse_ll_bounds(argv[4], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    reset = parse_ll_bounds(argv[5], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr,
+        LP5523_INS_END(interrupt, reset));
+}
+
+static int
+lp5523_shell_cmd_ins_trigger(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t wait_external;
+    uint8_t wait_engines;
+    uint8_t send_external;
+    uint8_t send_engines;
+
+    if (argc > 8) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 8) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    wait_external = parse_ll_bounds(argv[4], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    wait_engines = parse_ll_bounds(argv[5], 0, 7, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    send_external = parse_ll_bounds(argv[6], 0, 1, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[6]);
+    }
+
+    send_engines = parse_ll_bounds(argv[7], 0, 7, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[7]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr,
+        LP5523_INS_TRIGGER(wait_external, wait_engines, send_external,
+            send_engines));
+}
+
+static int
+lp5523_shell_cmd_ins_j(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t skip;
+    uint8_t variable1;
+    uint8_t variable2;
+
+    if (argc > 7) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 7) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    skip = parse_ll_bounds(argv[4], 0, 31, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    variable1 = parse_ll_bounds(argv[5], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    variable2 = parse_ll_bounds(argv[6], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[6]);
+    }
+
+    if (strcmp(argv[3], "jne") == 0) {
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_JNE(skip, variable1, variable2));
+    }
+    if (strcmp(argv[3], "jl") == 0) {
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_JL(skip, variable1, variable2));
+    }
+    if (strcmp(argv[3], "jge") == 0) {
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_JGE(skip, variable1, variable2));
+    }
+    if (strcmp(argv[3], "je") == 0) {
+        return lp5523_set_instruction(&lp5523_itf, addr,
+            LP5523_INS_JE(skip, variable1, variable2));
+    }
+
+    return lp5523_shell_err_invalid_arg(argv[3]);
+}
+
+static int
+lp5523_shell_cmd_ins_ld(int argc, char **argv, uint8_t addr)
+{
+    int rc;
+    uint8_t target;
+    uint8_t value;
+
+    if (argc > 6) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 6) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    target = parse_ll_bounds(argv[4], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    value = parse_ll_bounds(argv[5], 0, 255, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr,
+        LP5523_INS_LD(target, value));
+}
+
+static int
+lp5523_shell_cmd_ins_add_sub(int argc, char **argv, uint8_t addr, uint8_t sub)
+{
+    int rc;
+    uint8_t target;
+    uint8_t variable1;
+    uint8_t variable2;
+
+    if (argc > 7) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    } else if (argc < 7) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    if (strcmp(argv[4], "im") == 0) {
+        target = parse_ll_bounds(argv[5], 0, 3, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[5]);
+        }
+
+        variable1 = parse_ll_bounds(argv[6], 0, 255, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[6]);
+        }
+
+        return lp5523_set_instruction(&lp5523_itf, addr, (sub != 0) ?
+            LP5523_INS_SUB_IM(target, variable1) :
+            LP5523_INS_ADD_IM(target, variable1));
+    }
+    target = parse_ll_bounds(argv[4], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[4]);
+    }
+
+    variable1 = parse_ll_bounds(argv[5], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[5]);
+    }
+
+    variable2 = parse_ll_bounds(argv[6], 0, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[6]);
+    }
+
+    return lp5523_set_instruction(&lp5523_itf, addr, (sub != 0) ?
+        LP5523_INS_SUB(target, variable1, variable2) :
+        LP5523_INS_ADD(target, variable1, variable2));
+}
+
+static int
+lp5523_shell_cmd_ins_add(int argc, char **argv, uint8_t addr)
+{
+    return lp5523_shell_cmd_ins_add_sub(argc, argv, addr, 0);
+}
+
+static int
+lp5523_shell_cmd_ins_sub(int argc, char **argv, uint8_t addr)
+{
+    return lp5523_shell_cmd_ins_add_sub(argc, argv, addr, 1);
+}
+
+static int
+lp5523_shell_cmd_ins(int argc, char **argv)
+{
+    int rc;
+    uint8_t addr;
+
+    if (argc < 4) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    /* get addr */
+    addr = parse_ll_bounds(argv[2], 0, 95, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+
+    if (strcmp(argv[3], "ramp") == 0) {
+        return lp5523_shell_cmd_ins_ramp(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "pwm") == 0) {
+        return lp5523_shell_cmd_ins_pwm(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "wait") == 0) {
+        return lp5523_shell_cmd_ins_wait(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "mux") == 0) {
+        return lp5523_shell_cmd_ins_mux(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "rst") == 0) {
+        return lp5523_shell_cmd_ins_rst(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "branch") == 0) {
+        return lp5523_shell_cmd_ins_branch(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "int") == 0) {
+        return lp5523_shell_cmd_ins_int(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "end") == 0) {
+        return lp5523_shell_cmd_ins_end(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "trigger") == 0) {
+        return lp5523_shell_cmd_ins_trigger(argc, argv, addr);
+    }
+
+    if (argv[3][0] == 'j') {
+        return lp5523_shell_cmd_ins_j(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "ld") == 0) {
+        return lp5523_shell_cmd_ins_ld(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "add") == 0) {
+        return lp5523_shell_cmd_ins_add(argc, argv, addr);
+    }
+
+    if (strcmp(argv[3], "sub") == 0) {
+        return lp5523_shell_cmd_ins_sub(argc, argv, addr);
+    }
+
+    return lp5523_shell_err_unknown_arg(argv[2]);
+}
+
+static int
+lp5523_shell_cmd_start(int argc, char **argv)
+{
+    int rc;
+    uint8_t engine;
+    uint8_t addr;
+
+    if (argc < 4) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    } else if (argc > 5) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    /* set start address for engine */
+    engine = parse_ll_bounds(argv[2], 1, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+
+    addr = parse_ll_bounds(argv[3], 0, 95, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[3]);
+    }
+
+    return lp5523_set_engine_reg(&lp5523_itf,
+        LP5523_ENG_PROG_START_ADDR, engine, addr);
+}
+
+static int
+lp5523_shell_cmd_load(int argc, char **argv)
+{
+    int rc;
+    uint8_t engine;
+    uint8_t engines;
+
+    if (argc < 3) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    } else if (argc > 3) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    /* engine to load mode */
+    engine = parse_ll_bounds(argv[2], 1, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+    engines = 3 << ((3 - engine) << 1);
+
+    /* disable engines */
+    rc = lp5523_set_engine_control(&lp5523_itf, LP5523_ENGINE_CNTRL2, engines,
+        LP5523_ENGINES_DISABLED);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* put engines into load program state */
+    return lp5523_set_engine_control(&lp5523_itf, LP5523_ENGINE_CNTRL2, 
engines,
+        LP5523_ENGINES_LOAD_PROGRAM);
+}
+
+static int
+lp5523_shell_cmd_run(int argc, char **argv)
+{
+    int rc;
+    uint8_t engine;
+
+    if (argc < 3) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    } else if (argc > 3) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    /* engine run */
+    engine = parse_ll_bounds(argv[2], 1, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+
+
+    return lp5523_engines_run(&lp5523_itf, 3 << ((3 - engine) << 1));
+}
+
+static int
+lp5523_shell_cmd_hold(int argc, char **argv)
+{
+    int rc;
+    uint8_t engine;
+
+    if (argc < 3) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    } else if (argc > 3) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    /* engine hold */
+    engine = parse_ll_bounds(argv[2], 1, 3, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+
+    return lp5523_engines_hold(&lp5523_itf, 3 << ((3 - engine) << 1));
+}
+
+static int
+lp5523_shell_cmd_dump(int argc, char **argv)
+{
+    int rc;
+    uint8_t i;
+    uint16_t ins;
+
+    if (argc < 2) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    } else if (argc > 2) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    i = 0;
+    while (i < LP5523_MEMORY_SIZE) {
+        rc = lp5523_get_instruction(&lp5523_itf, i, &ins);
+        if (rc != 0) {
+            return -1;
+        }
+        console_printf("%02x: %04x\r\n", i, ins);
+        ++i;
+    }
+
+    return 0;
+}
+
+static int
+lp5523_shell_cmd_reg(int argc, char **argv)
+{
+    int rc;
+    uint8_t addr;
+    uint8_t value;
+
+    if (argc < 3) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    } else if (argc > 4) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    addr = parse_ll_bounds(argv[2], 0, 255, &rc);
+    if (rc != 0) {
+        return lp5523_shell_err_invalid_arg(argv[2]);
+    }
+
+    if (strcmp(argv[2], "set") == 0) {
+        if (argc < 4) {
+            return lp5523_shell_err_too_few_args(argv[1]);
+        }
+
+        value = parse_ll_bounds(argv[3], 0, 255, &rc);
+        if (rc != 0) {
+            return lp5523_shell_err_invalid_arg(argv[3]);
+        }
+
+        return lp5523_set_reg(&lp5523_itf, addr, value);
+    }
+
+    if (argc > 3) {
+        return lp5523_shell_err_too_many_args(argv[1]);
+    }
+
+    rc = lp5523_get_reg(&lp5523_itf, addr, &value);
+    if (rc != 0) {
+        return rc;
+    }
+
+    console_printf("%02x\r\n", value);
+    return rc;
+}
+
+static int
+lp5523_shell_cmd(int argc, char **argv)
+{
+    if (argc == 1) {
+        return lp5523_shell_help();
+    }
+
+    if (argc < 1) {
+        return lp5523_shell_err_too_few_args(argv[1]);
+    }
+
+    /* Reset */
+    if (strcmp(argv[1], "reset") == 0) {
+        return lp5523_shell_cmd_reset(argc, argv);
+    }
+
+    /* Enables the device or an output */
+    if (strcmp(argv[1], "enable") == 0) {
+        return lp5523_shell_cmd_enable(argc, argv);
+    }
+
+    /* Disables the device or an output */
+    if (strcmp(argv[1], "disable") == 0) {
+        return lp5523_shell_cmd_disable(argc, argv);
+    }
+
+    /* Sets the PWM duty cycle of an output LED */
+    if (strcmp(argv[1], "pwm") == 0) {
+        return lp5523_shell_cmd_pwm(argc, argv);
+    }
+
+    /* Writes an instruction */
+    if (strcmp(argv[1], "ins") == 0) {
+        return lp5523_shell_cmd_ins(argc, argv);
+    }
+
+    /* Sets program start */
+    if (strcmp(argv[1], "start") == 0) {
+        return lp5523_shell_cmd_start(argc, argv);
+    }
+
+    /* Sets engines into load program mode */
+    if (strcmp(argv[1], "load") == 0) {
+        return lp5523_shell_cmd_load(argc, argv);
+    }
+
+    /* Runs program */
+    if (strcmp(argv[1], "run") == 0) {
+        return lp5523_shell_cmd_run(argc, argv);
+    }
+
+    /* Holds program */
+    if (strcmp(argv[1], "hold") == 0) {
+        return lp5523_shell_cmd_hold(argc, argv);
+    }
+
+    /* dumps program */
+    if (strcmp(argv[1], "dump") == 0) {
+        return lp5523_shell_cmd_dump(argc, argv);
+    }
+
+    if (strcmp(argv[1], "reg") == 0) {
+        return lp5523_shell_cmd_reg(argc, argv);
+    }
+
+    return lp5523_shell_err_unknown_arg(argv[1]);
+}
+
+int
+lp5523_shell_init(void)
+{
+    int rc;
+
+    rc = shell_cmd_register(&lp5523_shell_cmd_struct);
+
+    return rc;
+}
+
+#endif
diff --git a/hw/drivers/lp5523/syscfg.yml b/hw/drivers/lp5523/syscfg.yml
new file mode 100644
index 000000000..416f0a483
--- /dev/null
+++ b/hw/drivers/lp5523/syscfg.yml
@@ -0,0 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.defs:
+    LP5523_CLI:
+        description: 'Enable shell support for the LP5523'
+        value: 0
+    LP5523_SHELL_ITF_TYPE:
+        description: 'LP5523 interface type'
+        value: 1
+    LP5523_SHELL_ITF_NUM:
+        description: 'LP5523 interface number'
+        value: 0
+    LP5523_SHELL_ITF_ADDR:
+        description: 'LP5523 I2C Address'
+        value: 0x32
\ No newline at end of file


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to